Astral Realms Documentation Help

Resources

A resource is a secondary, regenerating numeric pool tracked per online player — separate from Stats, but capped and fed by them. AstralStats ships one resource (SHIELD) out of the box; server owners can add more by editing resources.yml.

Resource types

ResourceType is a fixed Java enum — new types cannot be added without a plugin update, only configured (or left unconfigured) via resources.yml:

Value

Notes

HEALTH

Special-cased — not a tracked PlayerResource at all. /stats resource add/timed operate directly on the vanilla MAX_HEALTH attribute and Player#setHealth/getHealth instead of going through ResourceService. Timed effects are rejected for HEALTH (see Manual manipulation).

MANA

Regular resource type. Unconfigured by default — has no effect until added to resources.yml.

STAMINA

Regular resource type. Unconfigured by default.

SHIELD

Regular resource type. Shipped and configured by default (see Shipped resource: Shield).

CHARGE

Regular resource type. Unconfigured by default.

ResourceType.fromName(String) matches case-insensitively and throws IllegalArgumentException for an unknown name; it backs both the /stats resource command argument and the %stats_resource_<type>% placeholder (see Placeholders).

Configuration (resources.yml)

resources.yml has a single top-level key, resources — a map of ResourceTypeResourceBlueprint. Any ResourceType not present in the map is simply never tracked for players.

resources: SHIELD: off-combat-only: true type: MAXIMUM max-stat: "astralstats:max_shield" regeneration-stat: "astralstats:shield_regeneration"

ResourceBlueprint fields

Field

Type

Required

Description

off-combat-only

boolean

Yes

When true, regeneration returns 0 while the player is in combat (see Combat interaction).

type

MISSING/MAXIMUM/FLAT

Yes

Selects the regeneration formula — see Regeneration formula.

max-stat

Key

Yes

Namespaced key of the stat that defines this resource's maximum (and is used to clamp the resource's value). Resolved via AstralStats#stats().statValue(...) — see Stats & Modifiers.

regeneration-stat

Key

Yes

Namespaced key of the stat that defines this resource's regeneration rate — same resolution mechanism as max-stat.

base-value

PlaceholderWrapper<Double>

No

Starting value on player load. Accepts %placeholders%, resolved against the loading player's placeholder container. When omitted (or when it resolves to null), the resource instead starts at the current max-stat value.

type

type selects which of three formulas PlayerResource.regeneration uses every tick — see Regeneration formula for the exact math. resources.yml's inline comment only mentions MAXIMUM/MISSING, but the enum (ResourceBlueprint.Type) also defines FLAT.

Regeneration formula

Each PlayerResource computes its regeneration amount for the current tick from its blueprint's type, its regeneration-stat value (regenStat), and its max-stat value (max):

type

Formula

MAXIMUM

max * (regenStat / 100) — regen is a percentage of the resource's maximum.

MISSING

(max - amount) * (regenStat / 100) — regen is a percentage of the missing amount (asymptotic climb toward max).

FLAT

regenStat — regen is applied as a flat amount per tick, ignoring max.

Combat interaction

Before applying any formula, PlayerResource.regeneration short-circuits to 0 when both are true:

  • blueprint.off-combat-only() is true, and

  • the player is currently in combat (CombatService.isInCombat).

A player is considered "in combat" for combat-cooldown (default 10s) after last taking damage — see Combat Mechanics for the full combat-state model. This check is per-tick, so regeneration resumes automatically the instant combat state clears, without any extra bookkeeping on the resource itself.

Tick cadence & lifecycle

  • ResourceUpdateTask runs asynchronously every 5 ticks (Bukkit.getScheduler().runTaskTimerAsynchronously, period 5L) and calls ResourceContainer.tick(plugin, player) for every online player with a loaded resource container.

  • ResourceContainer.tick iterates the player's resources and, per resource, only proceeds if at least 1000ms have elapsed since that resource's lastUpdate — so each individual resource regenerates at most once per second, independent of the 5-tick (250ms) scheduler cadence. lastUpdate is refreshed to "now" every time this 1-second gate is passed, whether or not the computed regen amount was non-zero.

  • Clamping happens in PlayerResource.update: the new amount is floored to 0, then capped to the resource's live max-stat value (re-read from AstralStats#stats() on every update call, so it tracks stat modifiers in real time).

Load-time initialization

When a player's resources are loaded (ResourceService.load), each configured ResourceType gets a fresh PlayerResource whose starting amount is:

  • the resolved base-value (evaluated against the player's placeholder container), if the blueprint sets one, otherwise

  • the player's current max-stat value.

Shipped resource: Shield

The default resources.yml configures exactly one resource, SHIELD:

resources: SHIELD: off-combat-only: true type: MAXIMUM max-stat: "astralstats:max_shield" regeneration-stat: "astralstats:shield_regeneration"

It is backed by two shipped stat blueprints under blueprints/shield/:

File

key

base

min

max

max-shield.yml

astralstats:max_shield

50

0

500

shield-regeneration.yml

astralstats:shield_regeneration

1

0

500

With the defaults untouched, a player's shield regenerates max * (regen / 100) per eligible second — at base stat values, 50 * (1 / 100) = 0.5 shield/second — and only while out of combat, since off-combat-only is true. No base-value is set, so shield starts full (at max-stat) on join.

Shield damage absorption

ShieldListener handles EntityDamageEvent at EventPriority.HIGHEST with ignoreCancelled = true. For a damaged Player with finalDamage > 0:

  1. Looks up the player's SHIELD resource; if there is no resource container or no SHIELD resource configured, the event passes through untouched.

  2. If the current shield amount is <= 0, the event also passes through untouched (no absorption).

  3. Otherwise the shield soaks the damage:

    • If finalDamage >= shield: the event's damage is reduced to finalDamage - shield (the remainder is still dealt), and the shield is set to 0.

    • If finalDamage < shield: the event's damage is set to 0 (fully absorbed), and the shield is reduced by finalDamage.

  4. If the shield's amount is <= 0 after the update (i.e. it just depleted), the player hears Sound.ITEM_SHIELD_BREAK (category PLAYERS, volume 1.0, pitch 1.0).

Manual manipulation

/stats resource

Base permission stats.command.resource (class-level, applies to every subcommand below):

Subcommand

Syntax

Description

/stats resource list

<player>

Lists every tracked resource for the target player as TYPE: amount / max-stat.

/stats resource add

<player> <resourceType> <amount>

Adds amount to the resource. For HEALTH, this instead adjusts the player's vanilla health directly (clamped to MAX_HEALTH), bypassing ResourceService entirely.

/stats resource timed (alias temp)

<player> <resourceType> <amount> <durationMs>

Applies amount immediately and schedules the inverse after durationMs milliseconds, via TemporaryEffectService.addTimedResourceEffect. Rejected with an error message for HEALTH ("Timed effects on HEALTH are not supported"), and for non-positive durationMs or a non-finite amount.

Unless silent-command-success is enabled in config.yml, each successful add/timed sends a confirmation message to the command sender.

StatsAPI.resource(...)

The developer-facing entry points mirror the command surface:

double shield = StatsAPI.resource(player, ResourceType.SHIELD); // Drain 30 shield immediately StatsAPI.resource(player, ResourceType.SHIELD, current -> current - 30); // Drain 30 shield for 3 seconds, then restore it StatsAPI.addTimedResourceEffect(player, ResourceType.SHIELD, v -> v - 30, // apply v -> v + 30, // reverse 3_000L);

See Developer API for the full method signatures, including the offline-player (UUID) overloads and the reconnect/disconnect semantics of timed resource effects.

See also

Last modified: 25 July 2026