Astral Realms Documentation Help

Overview

AstralJobs is the professions plugin for AstralRealms. Each player levels up in a set of per-job professions — Farmer, Fisherman, Hunter, Lumberjack, Miner — by performing tracked world actions (breaking a block, killing a mob, catching a fish, smelting an ingot, …). Every tracked action grants experience and money, XP feeds a per-job Crunch equation that drives leveling, and each level unlocks a claimable reward. Timed boosters and permission-/API-driven modifiers can multiply or add to what a player earns on top of the base rates.

Jobs

A job is one YAML file under jobs/ (Job, loaded by JobService#load, one file per job, indexed by its id). AstralJobs ships five:

Job

id

Display name

Actions used

Farmer

farmer

Fermier

block-break, block-place, harvest-block, shear-block, gather-honey

Fisherman

fisherman

Pêcheur

fish, kill-entity, cook

Hunter

hunter

Chasseur

kill-entity

Lumberjack

lumberjack

Bûcheron

block-break, strip-block, cook

Miner

miner

Mineur

block-break, cook

Each job carries its own menu (menu-title, menu-icon, menu-secondary-icon), its own three leveling equations, its own actions map (material/entity key → action type → reward), and its own rewards map (level → description + action list). Nothing is shared between jobs at the config level — in the shipped configs all five happen to use the same leveling-equation constants, but each job is free to define its own. See Jobs for the full per-job YAML shape.

How earning works

ActionService registers one JobActionType per tracked Bukkit event and groups them by event class so only one listener per event is installed. Ten action types are registered, each under a fixed key that also appears as a sub-key in a job's actions map:

Key

Event

Fires on

block-break

BlockBreakEvent

Breaking a block not placed by a player; ageable blocks (crops) must be fully grown.

block-place

BlockPlaceEvent

Placing a block, keyed by the block placed.

harvest-block

PlayerHarvestBlockEvent

Harvesting a block (e.g. berry bushes) without breaking it.

shear-block

PlayerShearBlockEvent

Shearing a block (e.g. a pumpkin).

strip-block

EntityChangeBlockEvent

A player strips a log/wood block (target block tagged STRIPPED_*).

gather-honey

PlayerInteractEvent

Right-clicking a full beehive/bee nest with a glass bottle in hand.

kill-entity

EntityDeathEvent

A player lands the killing blow on an entity.

shear-entity

PlayerShearEntityEvent

Shearing an entity (e.g. a sheep).

fish

PlayerFishEvent

Reeling in a caught fish/item.

cook

FurnaceExtractEvent

Taking a cooked/smelted item out of a furnace, blast furnace, or smoker.

When a tracked event fires, the handler resolves the block/item/entity's Key, looks up cached actions for that action type + key across all jobs (JobService#findActionsByType), and — if any match — hands the rest of the work to a 2-thread worker pool so equation math and the level-up loop never run on the main thread. For every block-based action type other than block-place itself, a block that was placed by a player is skipped (BlockService#wasPlacedByPlayer, checked on the main thread since placement state can only be queried there) — so, for example, breaking a player-placed stone block doesn't grant Miner XP.

Each matched JobActionValue in a job's actions map defines a base reward (money) and experience value for that material/entity, multiplied by the item-stack amount where the action carries one (e.g. cooked item count). These base values are run through the job's experience-progress-equation/experience-income-equation, then through any active modifiers, before being applied. A cancellable JobExperienceGainEvent and JobMoneyGainEvent fire for each gain, letting other plugins veto or rewrite the amount before it lands.

Leveling model

Each job defines three Crunch expressions, compiled once per job and evaluated per action:

Equation

Variables

Purpose

level-progress-equation

level

Total XP required to reach level — a piecewise polynomial in the shipped jobs, banded by level range (0–1, 1–25, 25–50, …), each band scaled by 1 + (level-1)*0.08.

experience-progress-equation

level, experience

Turns a raw action XP value into the XP actually granted — shipped as experience*(1+(level-1)*0.08).

experience-income-equation

level, income

Turns a raw action money value into the money actually granted — shipped as income*(1+(level-1)*0.08).

On every matched action, ActionService snapshots the player's (level, experience) for that job, computes the XP/money gain through the equations above, applies experience, then loops job.computeLevelProgress(level + 1) — leveling up (firing a cancellable JobLevelUpEvent each time) while accumulated experience covers the next threshold. The loop is bounded by max-level in config.yml (default 200); a max-level <= 0 is treated as uncapped. Once computeLevelProgress returns a non-positive value the equation's domain is exhausted and the player is treated as maxed, so an uncapped config can't spin forever. Players past the cap keep accumulating XP but stop gaining levels.

Rewards

Each job's rewards map keys a level to a JobReward: a description (component list, shown in the job menu) and an actions list run through the AstralCore action framework — typically a [message] line per item/currency plus a [console] line that actually grants it (eco give, give, permission grants, …). Rewards are not granted automatically on level-up; a player claims them via:

  • /jobs claim — claims every reward across every job whose level requirement is met and not yet claimed.

  • The claim-job-reward AstralCore action, registered by the plugin on enable — takes a job and a level as parameters and claims that one job/level reward, for use from a menu button.

Claim state is tracked per player as JobsPlayerData (a Map<String jobId, Set<Integer> claimedLevels>), registered with AstralSync as the astraljobs:data snapshot adapter (JobsSnapshotAdapter) — it round-trips through Sync's binary snapshot format rather than a local table, so claimed rewards follow the player across servers. See Jobs for the reward YAML shape.

Boosters and modifiers

Two independent systems multiply or add to a player's XP/money gain, both consumed through ModifierService:

  • Boosters — timed, consumable items. A BoosterBlueprint (one entry per file under boosters/, BoosterBlueprintService) defines a type (EXPERIENCE, MONEY, or BOTH), a scope (INDIVIDUAL or GLOBAL), a duration, a multiplier, and the item it's represented by. Activating one (BoosterService#use) converts the multiplier into a RELATIVE JobModifier applied for the booster's duration; GLOBAL boosters apply to every online player and queue back-to-back if one is already running. A BoosterWatchdogTask polls for activation/expiry, firing BoosterActivateEvent/BoosterExpiredEvent. See Boosters.

  • ModifiersJobModifiers stacked per player in ModifierService, each scoped to EXPERIENCE, MONEY, or GLOBAL and typed RELATIVE (percentage, combined multiplicatively) or ABSOLUTE (flat, summed). Two sources feed modifiers automatically:

    • permissions-boosters in config.yml — maps a permission node to an EXPERIENCE/MONEY multiplier, applied on join (BoosterService#applyPermissionModifiers) for every permission the player holds.

    • Boosters themselves, as described above. Other plugins can add/remove/query modifiers directly through JobsAPI.

Integrations

  • AstralHud (soft-dependency) — AstralHudHook wraps the XP-gain action-bar component with AstralHud's background renderer when present. NotificationService batches XP/money gains per player+job (350 ms cooldown, 5 s stale timeout) and sends them as a raw WrapperPlayServerActionBar packet via packetevents, independent of the standard Bukkit action-bar API.

  • AstralAnalyticsAnalyticsListener logs a job_level_up event on every level-up; NotificationService#flush logs a job_experience_notification event (accumulated XP/income/levels) each time a batched notification is persisted.

  • LeaderboardsLeaderboardListener pushes a player's new level into LeaderboardService on level-up, using the leaderboards map in config.yml (job id → leaderboard id; shipped with all five jobs mapped to jobs-<job>).

  • Item stack supplier — booster items are exposed to AstralCore's item-stack-supplier registry under namespace jobs (JobsBoostersItemSupplier, registered as CommonRegistries.itemStackSuppliers()), so other plugins/menus can reference a booster item as jobs:<blueprint-id>.

Dependencies

Dependency

Required

Notes

AstralCore

Yes

AstralPaperPlugin base, menus, actions, placeholders, configuration loading.

AstralSync

Yes

Persists JobsPlayerData (claimed rewards) across servers.

packetevents

Yes

Sends the batched XP/money action-bar notification as a raw packet.

AstralHud

Soft

When present, adds a background to the action-bar notification.

Where to go next

  • Configurationconfig.yml: max-level, permissions-boosters, leaderboards, action displays.

  • Commands/jobs, /jobs level, /jobs experience.

  • Jobs — the per-job YAML shape: menu, leveling equations, actions, rewards.

  • Boosters — booster blueprint YAML and activation flow.

  • Placeholders — the %job_*%, %jobs_*%, %booster_*% namespaces.

  • Messages — the message-key catalogue.

  • Developer APIJobsAPI, events, and the claim-job-reward action.

Last modified: 25 July 2026