Astral Realms Documentation Help

Messages

plugins/AstralJobs/messages.yml holds every player-facing string the plugin sends. It's loaded into the JobsMessages enum on enable (loadEnum("messages.yml", JobsMessages.class)), so keys are kebab-case (LEVEL_UPlevel-up) and values are MiniMessage strings that resolve the standard AstralCore variable tags (<success>, <warning>, <error>, plus server-defined ones like <secondary_color>/<text_color>) and any placeholder reachable from the container the message is sent with.

Default file

level-up: "<success>Vous êtes passé au niveau <#26d971>%level% <#80ed99>dans le métier de <#26d971>%job% <#80ed99>! Récupérez votre récompense dans le <#26d971>/metier<#80ed99>." experience-gained: "<font:hud:icons>f</font> <font:hud:shift_1><gray><#26d971>%income% <gray>| <white><font:hud:icons>g</font> <gray><#26d971>%experience% <gray>| <#26d971>%current%<gray>/<#26d971>%total%" # Boosters same-type-booster-active: "<warning>Vous avez déjà un élixir d'activé du même type. Veuillez attendre qu'il expire avant d'en activer un autre." # -- Personal personal-booster-activated: "<success>Votre <secondary_color>%booster_formattedType% <#80ed99>a été activé pour <secondary_color>%booster_remainingTime% <#80ed99>!" personal-booster-expired: "<warning>Votre <secondary_color>%booster_formattedType% <#ffd60a>a expiré." # -- Global global-booster-activated: "<success>Votre booster <secondary_color>%booster_formattedType% <#80ed99>a été activé pour <secondary_color>%booster_remainingTime% <#80ed99>!" global-booster-activated-notification: "<succes>Un booster <secondary_color>%booster_formattedType% <#80ed99>a été activé pour <secondary_color>%booster_remainingTime% <#80ed99>!" global-booster-queued: "<success>Votre booster <secondary_color>%booster_formattedType% <#80ed99>a été mis en attente il sera activé dans <secondary_color>%time% <#80ed99>!" global-booster-expired: "<warning>Votre booster <secondary_color>%booster_formattedType% <#ffd60a>a expiré." # Boosters types type-experience: "Élixir d'experience" type-money: "Élixir de richesse" type-global: "Élixir global" # Rewards reward-cannot-be-claimed: "<warning>Vous ne pouvez récupérer cette récompense. Vous devez passer niveau <#26d971>%level% <#ffd60a>pour la récupérer." no-rewards-available: "<warning>Il n'y a pas de récompense disponible." # Jobs info job-info-header: "<gold>--- <primary_color>Métiers - Niveau totaux %levels% <gold>---" job-info-entry: "<secondary_color>%job% <text_color>Niveau <secondary_color>%level% <text_color>| Experience: <secondary_color>%current%<text_color>/<secondary_color>%required%" job-info-footer: "" # Miscellaneous unexpected-error: "<error>Une erreur est apparue. Veuillez réessayer plus tard."

Progression

Key

Placeholders

Sent to

When

level-up

%level%, %job%

Player

Once per level gained, inside ActionService's level-up loop — a single action that crosses several thresholds fires this once per threshold crossed. %level% is the new level; %job% is the job's configured display-name.

experience-gained

%income%, %experience%, %current%, %total%

Player, action bar

Rendered as a raw action-bar packet (WrapperPlayServerActionBar via PacketEvents, not sendActionBar) by NotificationService#sendNotification. A background is spliced in via AstralHudHook#addBackground when AstralHud is present (see Overview → Integrations).

experience-gained isn't sent per XP gain — ActionService accumulates every surviving experience/money gain for a player+job into a NotificationEntry (NotificationService#update), and a repeating task (NotificationRenderTask, every 5 ticks) re-renders the action bar for any entry that hasn't rendered in the last 350 ms (NOTIFICATION_COOLDOWN_MS) and has updated within the last 5 s (STALE_TIMEOUT_MS). Past that 5 s idle window the entry is flushed and dropped instead (NotificationCleanUpTask) — see Jobs → Level-up flow for the full accumulate/flush cycle.

Boosters

Key

Placeholders

Sent to

When

same-type-booster-active

Player

BoosterService#use finds the player already has an active/queued booster of the same type and scope as the item being used (BoosterRepository#hasActiveBooster). The item is refunded to the player's mailbox. The blueprint's %booster_*% chain is registered on the container even though the default text doesn't use it.

personal-booster-activated

%booster_formattedType%, %booster_remainingTime%

Player

An INDIVIDUAL-scope booster is created and saved successfully in BoosterService#use.

personal-booster-expired

%booster_formattedType%

Owner

The watchdog's BoosterService#expire deletes an INDIVIDUAL booster whose owner is currently online.

global-booster-activated

%booster_formattedType%, %booster_remainingTime%

Player (purchaser)

Sent immediately in BoosterService#use whenever a GLOBAL-scope booster is created — regardless of whether it starts immediately or is queued behind an already-running global of the same type (see note below). Sent again to the same player from BoosterService#activate if that booster later crosses activatesAt on a watchdog tick (i.e. it really was queued).

global-booster-activated-notification

%booster_formattedType%, %booster_remainingTime%

Every other online player

BoosterService#activate fires this to everyone except the owner the first time a GLOBAL booster crosses activatesAt.

global-booster-queued

%booster_formattedType%, %time%

Defined in messages.yml and the JobsMessages enum but not referenced by any code path as of this reading — see note below.

global-booster-expired

%booster_formattedType%

Owner

The watchdog's BoosterService#expire deletes a GLOBAL booster whose owner is currently online.

See Placeholders → booster_* (active) for the full BoosterEntity placeholder catalogue, including why %booster_remainingTime% is a raw millisecond count.

Booster type labels

%booster_formattedType% on an active booster resolves to one of these three keys via BoosterType#message (BoosterTypeJobsMessages):

BoosterType

Key

Default text

EXPERIENCE

type-experience

Élixir d'experience

MONEY

type-money

Élixir de richesse

BOTH

type-global

Élixir global

Rewards

Key

Placeholders

Sent to

When

reward-cannot-be-claimed

%level%

Player

The claim-job-reward action runs for a level the player hasn't reached yet. %level% is the reward's required level, not the player's current one.

no-rewards-available

Player

/jobs claim finds no unclaimed reward at or below the player's current level, across any job.

Jobs info

Sent in sequence by /jobs info: one job-info-header, then one job-info-entry per job the player has a JobLevelEntity for, then one job-info-footer.

Key

Placeholders

When

job-info-header

%levels%

First line. %levels% is the sum of the player's level across every job.

job-info-entry

%job%, %level%, %current%, %required%

One per job. %current% and %required% are the player's experience and the XP needed for the next level (job.computeLevelProgress(level + 1)), both formatted to two decimals — the same threshold used by the level-up loop, so this always agrees with when the next level-up message will fire.

job-info-footer

Last line. Shipped as an empty string, so by default it renders nothing.

Miscellaneous

Key

Placeholders

Sent to

When

unexpected-error

Player

Generic catch-all: menu-open failure on /jobs, missing JobsPlayerData on /jobs claim or the claim-job-reward action, no JobLevelEntity at all on /jobs info, or a BoosterRepository check/save failure in BoosterService#use. The triggering exception is always logged server-side.

Last modified: 25 July 2026