Skip to main content

Resource (resource)

A resource is one number stored per entity: its bounds, and how it is shown. It does not care where the number comes from or what it is for. Everything that turns a number into a cultivation resource — the realm chain entry, natural regeneration, the aura marker, the conversions to and from cultivation progress, the gate on when it may be spent — lives in aura, and an aura definition points back at this value through its resource field. A value with no matching aura definition is a plain counter.

File Location​

Resource files go in data/<namespace>/saturn/resource/ inside your datapack. The filename is its ID, so data/example/saturn/resource/qi.json has the ID example:qi.

Fields​

FieldTypeDefaultDescription
default_valueNumberProviderrequiredThe current value when the attachment is created.
minNumberProvider0Lower bound of the value.
maxNumberProviderrequiredUpper bound of the value.
iconIcon ReferencenoneOptional icon, drawn on this value's entry on the wheel.
particle_colorRGBColor#FFFFFFParticle colour used by spirit power rays. Written as #RRGGBB (an integer or an [r,g,b] float array is accepted too); always treated as opaque.
barsResource bar list[]Inline resource bars; when empty, the value is not displayed.

A value can be spent as the saturn:resource entry of a cost array (see Shared Data Types · Cost), compared with mxt:resource_compare (it tests whether the current value is ≥ the min you write; there is no upper-bound comparison), read in a formula as caster_<flattened value id> (see Formula Variables), raised or lowered by the mxt:add_resource action, and stored into an item as the aura this value corresponds to (its aura definition). What an item can hold is an aura: the access interfaces exchange aura identities, so a counter with no aura definition cannot go into an item — but it still enters the player's own pool, because a pool is keyed by the value.

min and max are evaluated again on initialisation and on every change. The write goes through only when both are finite and min <= max; when that does not hold the whole operation fails — nothing is written, and it does not fall back to the default value either. A change that is not finite is not written either.

An out-of-range change is clamped to the bound rather than rejected: clamping only alters the result that lands, it does not fail the operation.

max can be a formula:

// data/example/saturn/resource/qi.json
{
"default_value": 0,
"max": "100 + realm_rank * 20 + absorbed_aura * 0.1",
"particle_color": "#66CCFF",
"bars": [
{
"context": "mxt:self_hud",
"anchor": "left",
"order": 0,
"renderer": {"type": "mxt:boss_bar", "bar_index": 1}
}
]
}

The realm variables a formula may use (realm_rank, absorbed_aura, level) exist only inside the chain of the aura definition this value belongs to.

Use mxt:conditional when the maximum has to differ by player condition: branches are checked in order, and fallback takes only a number or an expression string and is used when there is no player or no branch matches; with no fallback it returns 0.

resource.bars​

bars is an inline array of resource, not a datapack registry of its own.

context uses IDs from the built-in saturn:resource_bar_context registry. A context extracts the current value, the minimum, the maximum and the time of the last change from the entity or the client state, and builds the display name from the resource ID passed in. The five built-ins are fixed — a datapack picks one, it cannot add its own: mxt:self_hud, mxt:target_overlay and mxt:boss_overlay read the value stored on the entity, while mxt:environment_concentration and mxt:actual_concentration read the aura pool synced to the client instead. The two concentration contexts mean "environment template only" and "environment, stock, blocks and formations all counted"; when saturn.resource.example.qi reads "Spirit Qi" in your language file, for example, the two display as environment spirit qi concentration and actual spirit qi concentration.

FieldTypeDefaultDescription
contextContext idmxt:self_hudWhere the numbers come from: extracts the value, builds the name and decides the layout.
anchorleft / rightrequiredWhether it lands in the left or the right column of the self HUD.
orderInteger0Within one column, smaller is closer to the vanilla hotbar.
visibilityVisibility objectmxt:alwaysWhen it is shown.
rendererRenderer objectrequiredHow it is drawn.
value_displayEnumnoneHow the numeric text is shown: none, current, current_and_maximum, percentage.
maximumPositive Doublecontext maximumOverrides the bar's display maximum only; it does not change the server-side or the context value.

The three contexts that read a stored value (mxt:self_hud, mxt:target_overlay, mxt:boss_overlay) report nothing while this value has not been initialised, and that bar is not drawn. A maximum that is not a finite positive number counts as not written — the context maximum is used as before, and nothing is reported at load time.

The two concentration contexts require this value to have an aura definition: with none, or with a pool whose maximum and current value are both non-positive, they report nothing and the bar is not drawn. Their minimum is always 0, and they record no last-changed time.

The two self HUD columns are dragged around by the player and their position is stored in the client config; a datapack only decides which of the two columns this bar lands in.

Resource bars go through NeoForge's GUI Layer and are drawn in the left or right column only; they never take the centre of the screen.

Renderers​

Every type, field, default, range and artwork form of the renderer family is in Resource Bar Renderers (resource_bar_render_data_type).

Visibility​

FieldTypeDefaultDescription
typeVisibility idrequiredWhich visibility condition to use.
hold_ticksLong60Read by mxt:recently_changed only: how long to keep showing after the last change; must be non-negative.
minDoublerequiredRead by mxt:resource_range only: inclusive lower bound, must be finite.
maxDoublerequiredRead by mxt:resource_range only: inclusive upper bound, must be finite and not below min.
valuesVisibility listrequiredRead by mxt:and / mxt:or only: the nested conditions.
valueVisibilityrequiredRead by mxt:not only: the condition to invert.

Visibility decides whether the bar is drawn and nothing else; it never changes how the value is settled. Which fields each visibility reads, and where its boundaries are, is in Resource Bar Visibility (resource_bar_visibility_type).

Two kinds of concentration

The IDs mxt:environment_concentration and mxt:actual_concentration exist in two places at once: written in bars[].context they are resource bar contexts, reading the aura pool synced to the client as described above; written as a resource value provider they are a different type, readable only with an entity — with no entity they are 0, and the server computes them from world state. The full list is in Resource Value Providers (resource_value_provider_type).

Display Names

Datapack definitions do not write a translation_key; the display name is generated from the identifier as <registry namespace>.<category>.<definition namespace>.<path>. The category of resource is resource, and this registry is hosted by the library (saturn:resource), so the registry namespace is saturn and the key starts with saturn.: example:qi looks up saturn.resource.example.qi. A / in the path goes into the key as written (example:foo/bar gives saturn.resource.example.foo/bar); sorting definitions into subdirectories per category does not add a second set of translation-key rules.

A resource definition has no writable text field: its name and description are both derived from the registered id by the rule above (the description being the name key plus .description), so giving this value words means translating those two keys.