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 |
|---|---|
| Special-cased — not a tracked |
| Regular resource type. Unconfigured by default — has no effect until added to |
| Regular resource type. Unconfigured by default. |
| Regular resource type. Shipped and configured by default (see Shipped resource: Shield). |
| 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 ResourceType → ResourceBlueprint. Any ResourceType not present in the map is simply never tracked for players.
ResourceBlueprint fields
Field | Type | Required | Description |
|---|---|---|---|
| boolean | Yes | When |
|
| Yes | Selects the regeneration formula — see Regeneration formula. |
| Key | Yes | Namespaced key of the stat that defines this resource's maximum (and is used to clamp the resource's value). Resolved via |
| Key | Yes | Namespaced key of the stat that defines this resource's regeneration rate — same resolution mechanism as |
|
| No | Starting value on player load. Accepts |
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):
| Formula |
|---|---|
|
|
|
|
|
|
Combat interaction
Before applying any formula, PlayerResource.regeneration short-circuits to 0 when both are true:
blueprint.off-combat-only()istrue, andthe 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
ResourceUpdateTaskruns asynchronously every 5 ticks (Bukkit.getScheduler().runTaskTimerAsynchronously, period5L) and callsResourceContainer.tick(plugin, player)for every online player with a loaded resource container.ResourceContainer.tickiterates the player's resources and, per resource, only proceeds if at least 1000ms have elapsed since that resource'slastUpdate— so each individual resource regenerates at most once per second, independent of the 5-tick (250ms) scheduler cadence.lastUpdateis 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 to0, then capped to the resource's livemax-statvalue (re-read fromAstralStats#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, otherwisethe player's current
max-statvalue.
Shipped resource: Shield
The default resources.yml configures exactly one resource, SHIELD:
It is backed by two shipped stat blueprints under blueprints/shield/:
File |
|
|
|
|
|---|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
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:
Looks up the player's
SHIELDresource; if there is no resource container or noSHIELDresource configured, the event passes through untouched.If the current shield amount is
<= 0, the event also passes through untouched (no absorption).Otherwise the shield soaks the damage:
If
finalDamage >= shield: the event's damage is reduced tofinalDamage - shield(the remainder is still dealt), and the shield is set to0.If
finalDamage < shield: the event's damage is set to0(fully absorbed), and the shield is reduced byfinalDamage.
If the shield's amount is
<= 0after the update (i.e. it just depleted), the player hearsSound.ITEM_SHIELD_BREAK(categoryPLAYERS, volume1.0, pitch1.0).
Manual manipulation
/stats resource
Base permission stats.command.resource (class-level, applies to every subcommand below):
Subcommand | Syntax | Description |
|---|---|---|
|
| Lists every tracked resource for the target player as |
|
| Adds |
|
| Applies |
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:
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
Stats & Modifiers — how
max-stat/regeneration-statkeys resolve to live stat values.Combat Mechanics — the
combat-cooldownwindow that drivesoff-combat-onlypausing.Commands — full
/statscommand reference.Placeholders —
%stats_resource_<type>%.Developer API —
StatsAPI.resource(...)and timed resource effects.