Skip to main content

Define the Aura Environment

Define Aura and Realms left you with one zone that covers the whole Overworld with the same amount of aura. This page makes the world matter: denser regions, spirit stone veins, items you can burn while meditating, and the client-side presentation that tells a player where they are standing.

The previous tutorial must be finished first — everything here extends the same example:qi resource.

How the Numbers Fit Together​

Two different numbers are involved, and confusing them is the usual source of surprise:

NumberWhere it livesWhat it means
Chunk inventoryThe mxt:aura chunk attachmentWhat can actually be consumed at this position. Shared by every player in the chunk, regenerated by regen_per_tick.
Environment concentrationComputed from the matching zoneWhat the template says is here. Fluctuation and noise act on it, and it is what the client shows.

When a chunk is initialised, each resource starts at max(0, (amount + noise) / 10 - 5), where noise is the Perlin value of the template (or 0 when noise is off). The bare amount is therefore a base value ten times larger than the concentration it produces — a template with amount: 200 starts around 15. Capacity comes from max, which is resolved from that initial value unless you write a fixed number.

Cultivation progress and the aura a player gains are multiplied by the concentration multiplier at their position: concentration / maximum for a finite maximum, and concentration / (concentration + 1) for {"type": "mxt:unlimited"}.

What You Are Building​

FilePurpose
data/example/mxt/aura_zone/misty_valley.jsonA forest-level dense zone: concentration, noise, fluctuation and how it looks on the client.
data/example/mxt/block_aura/spirit_stone_ore.jsonLets a block add capacity to the chunk it sits in.
data/example/mxt/item_aura/spirit_stone.jsonLets an item be spent while cultivating and turn into aura.
kubejs/server_scripts/mxt_areas.jsCreates and removes artificial areas at runtime, and reads the resolved aura at a position.

Step 1 — A Denser Biome Zone​

Two overlapping templates are resolved level by level: biome < dimension < permanent manual area < formation. A later level replaces the aura values, element values, rules and display template of the earlier one entirely. Inside one level, the highest priority wins, and equal priorities are broken by taking the template with the lower ID, so the result is always reproducible.

That is why the two zones here are both biome-level: the forest template simply outranks the general one where it applies.

// data/example/mxt/aura_zone/misty_valley.json
{
"aura": {
"example:qi": {
"amount": 400,
"max": {"type": "mxt:initial_multiplier", "multiplier": 1.5},
"regen_per_tick": 0.1,
"color": "#7FE3C4"
}
},
"biomes": ["#minecraft:is_forest"],
"priority": 10,
"distribution": "realm_weighted",
"cultivate_condition": {
"type": "mxt:aura_range",
"aura": {"example:qi": {"min": 5, "max": 100000}}
},
"fluctuation": {
"enable": true,
"cycle_type": "day",
"amplitude": 0.3,
"offset_tick": 0
},
"noise": {
"enable": true,
"seed": 739430,
"scale": 640.0,
"amplitude": 5.0
},
"element_fit_bonus": 0.25,
"element_conflict_penalty": 0.2,
"client_render": {
"fog_color": "#7FE3C4",
"render_distance": 64,
"fog_strength": 0.35
},
"client_hud": {
"stored_aura": {"maximum": 60.0, "bar_index": 1, "anchor": "left", "order": 4},
"sensed_concentration": {"maximum": 60.0, "bar_index": 2, "anchor": "left", "order": 5}
}
}
FieldEffect
auraPer-aura inventory. The key set is the whole vocabulary of the zone: an environment has exactly the auras it lists, and each one's element is its own aura_type in the aura registry. The fields of one entry are on aura_zone, and the ways to compute max are on Aura Maximums.
priorityUsed only against other templates of the same level.
distributionrandom, equal or realm_weighted; it decides who gets how much when the chunk inventory cannot satisfy everyone. realm_weighted uses aura_share_weight from each player's realm stage.
cultivate_conditionAn entity condition the environment must satisfy for cultivation. Note that mxt:aura_range requires max on every aura entry.
fluctuationMultiplies the concentration by 1 + amplitude * sin(2π * (time + offset_tick) / cycle), with a 24000-tick day cycle or a 192000-tick moon cycle. It only affects the queried concentration, never the stored inventory.
noiseA seeded, reproducible Perlin offset so the map has gradients instead of hard borders. scale around 640–960 is recommended; amplitude: 5 gives roughly a -5..5 disturbance before the / 10 - 5 transform.
element_fit_bonus / element_conflict_penaltyAdjust the cultivation modifier of a spirit root: + element_fit_bonus when an aura whose aura_type is that root's element is present at the position. The penalty multiplies the opposition concentration - the sum of the other elements in the zone that have an overcomes / adapted_to relation with the root's element - so with no opposing element (or in an empty area) it is 0. Both default to 0.
client_renderFog colour, the distance it is applied over (8..256) and how strongly it replaces the vanilla fog (0..1). The strength is also scaled by the concentration, so thin aura looks fainter.
client_hudTwo optional bars: stored_aura reads the chunk inventory, sensed_concentration reads the environment template. They are drawn above the resource bars of the same side.

Rules​

The rules object adds environment policy:

"rules": {
"cultivate_suppress": false,
"tribulation_modify": 0.15,
"spirit_plant_bonus": 0.25,
"alchemy_env_bonus": true
}

cultivate_suppress aborts cultivation that is already running, and tribulation_modify injects the formula variable aura_tribulation_modifier into tribulation formulas. With alchemy_env_bonus on, alchemy inside the area counts as satisfying a recipe's minimum_aura requirement: the flag is a plain yes/no with no magnitude to scale an aura pool by, so it stands in for the requirement rather than enlarging the pool. spirit_plant_bonus applies to spirit herbs growing inside the area: the actual growth is growth_rate × max(0, 1 + bonus), multiplied in once, so herbs in this area grow faster and nowhere outside it is affected.

Step 2 — Aura From Blocks​

A spirit stone vein should be worth more than the ground it sits in.

// data/example/mxt/block_aura/spirit_stone_ore.json
{
"blocks": "mxt:spirit_stone_ore",
"aura": {
"example:qi": {"amount": 5.0, "max": 5.0, "regen_per_tick": 0.01}
}
}
// data/example/mxt/block_aura/spirit_stone_block.json
{
"blocks": "mxt:spirit_stone_block",
"aura": {
"example:qi": {"amount": 2.0, "max": 2.0, "regen_per_tick": 0.01}
}
}
  • Blocks are named in blocks: a single block id, a #block tag, or an array of either (tags expand at load time into whatever blocks they hold then). Every matching block in a chunk contributes once.
  • aura is the per-aura table mapping an aura ID to an amount: the keys are exactly the auras the block gives off, so a block cannot claim an aura it does not actually provide.
  • The file lives at data/example/mxt/block_aura/<name>.json, the entry id is example:<name>, and one file is one definition.
  • block_aura has no priority: when several definitions hit one block (another pack wrote it too, or one gives a tag and another the concrete block), they all apply and are added together.
  • The contribution does not consume the environment maximum: it raises the chunk's effective capacity by the same amount. An environment maximum of 30 with 30 points of ore becomes 60.
  • Queries look at a 7x7x7 range of sub-chunks: the inner 3x3x3 uses real block positions, the outer ring approximates with sub-chunk centres, and all of it decays by 1 / max(1, distance²).
  • Chunk loading rebuilds the block cache immediately, and break/place events update individual blocks immediately. Each section also has a random rescan target interval of 600..1199 ticks; due work is processed in order in batches each tick and may be delayed by a backlog. Server Config → Aura → Block Aura Period (default 10 ticks, 1..1200) controls the target interval for staggered stock regeneration, which uses actual elapsed time. Visitor counts update incrementally every tick; the setting does not control the rescan interval.

A common pattern is to make the natural template almost empty and let blocks provide the aura:

"aura": {
"example:qi": {"amount": 0, "max": {"type": "mxt:unlimited"}, "regen_per_tick": 0}
},
"noise": {"enable": true, "seed": 739430, "scale": 640.0, "amplitude": 5.0}

With amount: 0, most chunks sit at 0 after the / 10 - 5 transform, and only places with actual aura-emitting blocks stand out.

Step 3 — Aura From Items​

item_aura is a registry keyed by item, and it turns an item into cultivation fuel: while the player cultivates, the stack is drained tick by tick and its aura is released into the resource bar of the current realm.

// data/example/mxt/item_aura/spirit_stone.json
{
"items": "mxt:spirit_stone",
"type": "example:qi",
"aura": 100,
"consume_speed": "0.5 + caster_level * 0.05",
"release_speed": 2,
"exhausted_action": {"type": "mxt:no_op"}
}
// data/example/mxt/item_aura/spirit_fuel.json
{
"items": "#example:spirit_fuel",
"type": "example:qi",
"aura": 50,
"consume_speed": "0.5",
"release_speed": 1
}
  • Items are named in items: a single item id, a #item tag (tags expand at load time), or an array of either, so one file can cover a whole tag of fuel items; it also accepts ItemMatcher entries that carry a type. The required and optional fields are on item_aura.
  • The file lives at data/example/mxt/item_aura/<name>.json, the entry id is example:<name>, and one file is one definition.
  • When several definitions hit one item (another pack wrote it too, or one gives a tag and another the concrete item), the higher priority wins, and a tie falls back to registry order. priority defaults to 0.
  • type is the aura this item carries — the mxt:aura entry, not an element. The value the released aura is counted in is that aura's own resource, and its element is that aura's aura_type.
  • aura is the total per item, written into a server-side mxt:item_aura component (remain) on the stack when processing starts; the whole stack moves into the mxt:float_holding_item attachment for the duration. For an item that implements ItemAuraAccess it is instead the per-item charge ceiling.
  • Each tick the definition matched at that moment subtracts consume_speed × stack size from the remaining aura and charges release_speed × stack size into the realm's resource bar. Holding more items drains faster but lasts the same number of ticks.
  • A half-used stack is resumed before a fresh one is taken, and fresh stacks are taken in main hand, off hand, inventory order. When cultivation stops, the player logs out or dies, the stack is returned unchanged.
  • On exhaustion the item is removed and result_stack (if configured) is given back. Items implementing ItemAuraAccess (a spirit stone, for example) behave differently: they are charged and drained in place instead of being consumed, and a stack that carries no mxt:spirit_storage component counts as full.
info

The client does not draw a fuel bar, and never consumes items on its own.

Step 4 — Where It Shows Up​

PlaceWhat it shows
client_hud.stored_auraThe chunk inventory, as a real value that goes up and down with cultivation.
client_hud.sensed_concentrationThe environment template at the current position, including fluctuation and noise.
Resource bars with "context": "mxt:environment_concentration" / "mxt:actual_concentration"The same two numbers, but labelled after the resource, so saturn.resource.example.qi becomes environmental or actual aura concentration.
Fogclient_render, scaled by concentration.
ParticlesThe optional particle object on the template, refreshed every 5 ticks.

actual includes every source — template, chunk inventory, block aura and formations — while environment is only the template. The server syncs the position aura every Server Config → Aura → Sync Period ticks (5 by default) and the client only draws the snapshot.

On the command line:

/mxt aura query → every aura at your feet, with its element marker
/mxt aura query example:qi → one aura
/mxt aura vein → the size and tier of the connected spirit stone vein you stand on
/mxt aura cache clear 8 → rebuild the cached aura of nearby chunks (radius in chunks, default 3, 0..32)

Step 5 — Areas From a Script​

Biomes and dimensions cover the static world. For anything that has to be created at runtime — a blessing placed by a quest, a claimed area, a temporary field — use the KubeJS bridge:

// kubejs/server_scripts/mxt_areas.js
const area = MxtAura.addBox(
player.level, 'example:misty_valley',
0, 64, 0, // minimum corner
64, 128, 64, // maximum corner
10 // priority
)
console.info(`Created aura area ${area}`)

// Read the resolved aura at a position, including every source.
const aura = MxtAura.get(player.level, player.blockPosition())
console.info(`Concentration: ${aura.concentration()}, maximum: ${aura.maximum()}`)

// Later, or from another script:
// MxtAura.remove(player.level, area)

addBox needs a server level and a loaded aura_zone ID, and it returns the generated area ID. Manual areas are saved to the world, are the level above dimension bindings, and among themselves are resolved by priority. MxtAura.get is read-only and works on the client too, where it returns whatever state the client has received.

MxtEvents.auraZone fires with enter, leave, tick and override; override is the formation hand-off and can be cancelled to refuse it:

MxtEvents.auraZone(event => {
if (event.getKind() === 'override' && event.getConcentration() < 20) event.cancel()
})

Formations can also carry their own zone, which is the top level of the resolution order. The zone and the capacity bonus both live in an mxt:aura action on the formation:

{
"structure_template": "example:gathering_array",
"radius": 8,
"actions": [
{
"type": "mxt:aura",
"max_bonus": {"example:qi": 50},
"aura_zone": "example:misty_valley"
}
]
}

An active formation covers the area around its controller, so its aura_zone overrides every lower level, while max_bonus is added to the effective chunk maximum of the auras it names.

Verify​

Load the world again — these are data pack registries, so /reload does not pick them up — then run:

(load the world again)
/mxt registries validate
/mxt aura query example:qi → a forest should read higher than a plains
  1. Stand in a forest during the day and check /mxt aura query; sleep to night and check again. The value moved by up to ±30%, because of fluctuation.
  2. Walk a few hundred blocks in one direction. The value drifts smoothly, because of noise.
  3. Stand on spirit stone ore and run /mxt aura vein, then compare /mxt aura query before and after mining it out. The removable part is the block contribution.
  4. Cultivate while holding spirit stones. The bar fills noticeably faster than with empty hands, and the stack shrinks.
  5. If the fog is invisible, remember that fog_strength is multiplied by the concentration — a weak zone produces weak fog.

Common Mistakes​

SymptomCause
The zone never appliesIts biomes/dimensions are empty, and nothing references it. An empty list means "only through a manual area or a formation".
A specific zone is ignoredA dimension-level template outranks every biome-level one. Give the specific zone the same level as the general zone and a higher priority.
Aura is ten times weaker than amount suggestsamount is a base value: the initial concentration is amount / 10 - 5 before noise.
Block aura seems to do nothingIt adds capacity, not a visible concentration, to a chunk whose environment maximum is already high. Lower the template's amount and let blocks carry the difference.
Aura keeps resetting to the template valueFluctuation, noise and regeneration all recompute the template; the stored inventory only changes through cultivation, item fuel and regeneration.

Next​

Aura transfers, capacities, projectile amounts and crafting requirements support fractions. Pouring can fill a gap smaller than one unit and charges the amount actually moved. Interfaces and messages use two decimal places; calculations, persistence and synchronization keep full precision.