LogoKubeJS MNA

Registries

This page covers the current startup registration surface exposed by MnaJS.

mna:factions

Register with StartupEvents.registry("mna:factions", ...).

Use it for new factions with script-configurable grimoire, token, sounds, icon, colors, structure, and casting-resource routing.

Notable builder methods:

  • factionGrimoire(MnaItemId)
  • tokenItem(MnaItemId)
  • raidSound(MnaSoundId)
  • hornSound(MnaSoundId)
  • factionIcon(MnaTexture)
  • manaweaveRGB("rgb(116, 182, 79)")
  • sanctumStructure(MnaStructureId)
  • castingResources(MnaCastingResourceId...)
  • factionIconTextureSize(int)
  • maxModifierBonus(Attribute, float)
  • minModifierBonus(Attribute, float)
  • resourceSelector((player, availableResources) => ...)

Example:

StartupEvents.registry("mna:factions", (event) => {
event
.create("kubejs:verdant_court", "basic")
.factionGrimoire("minecraft:book")
.tokenItem("minecraft:emerald")
.raidSound("minecraft:event.raid.horn")
.factionIcon("mna:textures/gui/cantrips/ward.png")
.manaweaveRGB("rgb(116, 182, 79)")
.sanctumStructure("mna:multiblock/council_circle_of_power")
.castingResources("mna:mana", "mna:council_mana");
});

Notes:

  • manaweaveRGB accepts frontend-style color strings.
  • sanctumStructure is typed as a structure id, not a raw path hack.
  • resourceSelector is the deep hook for choosing which casting resource a player should use.

mna:ritual-effects

Register with StartupEvents.registry("mna:ritual-effects", ...).

Use it for the runtime handler that attaches behavior to a ritual recipe id.

Notable builder methods:

  • ritualName(MnaRitualId)
  • applicationTicks(int | callback)
  • applyEffect((context) => boolean)
  • matchReagents(...)
  • modifyReagents(...)
  • canStart(...)
  • applyStartCheckInCreative(boolean)
  • particles(...)
  • loopSound(...)

Example:

StartupEvents.registry("mna:ritual-effects", (event) => {
/**
* @type {Internal.CustomRitualEffect$Builder}
*/
const builder = event.create("kubejs:lightning_ritual_effect", "basic");
builder
.ritualName("kubejs:lightning_ritual")
.applicationTicks(20)
.applyEffect((context) => {
const level = context.getLevel();
if (level == null) return false;
const lightning = EntityType.LIGHTNING_BOLT.create(level);
if (lightning == null) return false;
lightning.setPos(context.getCenter().x, context.getCenter().y, context.getCenter().z);
level.addFreshEntity(lightning);
return true;
});
});

Notes:

  • Keep the builder in a typed local for Probe completion.
  • ritualName(...) should match the ritual recipe id you actually generate.

mna:components type basic

Register with StartupEvents.registry("mna:components", ...) and event.create(id, "basic").

Use it for a general spell effect component with fully scriptable applyEffect.

Notable builder methods:

  • guiIcon(MnaTexture)
  • affinity(Affinity)
  • initialComplexity(float)
  • addAttribute(Attribute, base, min, max, step, complexity)
  • baselineCooldown(int)
  • soundEffect(MnaSoundId)
  • factionRequirement(MnaFactionId)
  • addReagent(MnaItemId, ...)
  • addOptionalReagent(MnaItemId, ...)
  • applyEffect(...)
  • spawnParticles(...)
  • canBeCastAt(...)
  • getDescriptionTooltip(...)

Example:

StartupEvents.registry("mna:components", (event) => {
/**
* @type {Internal.CustomSpellEffect$Builder}
*/
const builder = event.create("kubejs:arcane_pulse", "basic");
builder
.guiIcon("mna:textures/gui/cantrips/ignite.png")
.affinity(Affinity.ARCANE)
.baselineCooldown(20)
.soundEffect("minecraft:entity.allay.item_given")
.factionRequirement("mna:council")
.addReagent("minecraft:lapis_lazuli")
.applyEffect((source, target, modificationData, context) => {
return ComponentApplicationResult.SUCCESS;
});
});

mna:components type damage

Use event.create(id, "damage").

This is the damage-oriented spell effect surface. It inherits most of the common component API and adds damage-specific attributes and callbacks.

Notable additions:

  • addDamageAttribute(base, min, max, step, complexity)
  • damageEntity((source, target, damage, context) => ...)
  • isTargetFriendly(...)
  • magnitudeHealthCheck(...)

Example:

/**
* @type {Internal.CustomDamageComponent$Builder}
*/
const builder = event.create("kubejs:searing_arc", "damage");
builder
.affinity(Affinity.FIRE)
.soundEffect("minecraft:entity.blaze.shoot")
.addDamageAttribute(4.0, 2.0, 8.0, 1.0, 1.0)
.addOptionalReagent("minecraft:blaze_powder")
.damageEntity((source, target, damage, context) => {
return ComponentApplicationResult.SUCCESS;
});

mna:components type potion

Use event.create(id, "potion").

This is the potion-effect component surface.

Notable builder methods:

  • effect(MnaMobEffectId)
  • modifiesDuration(boolean)
  • addDurationAttribute(base, min, max, step, complexity)
  • modifiesMagnitude(boolean)
  • addMagnitudeAttribute(base, min, max, step, complexity)
  • addPermanencyReagent(MnaItemId)
  • permanentFor(MnaFactionId...)

Example:

/**
* @type {Internal.CustomPotionEffectComponent$Builder}
*/
const builder = event.create("kubejs:swiftstep", "potion");
builder
.affinity(Affinity.WIND)
.effect("minecraft:speed")
.modifiesDuration(true)
.addDurationAttribute(60, 20, 180, 20, 1.0)
.modifiesMagnitude(true)
.addMagnitudeAttribute(1, 1, 3, 1, 1.25)
.addPermanencyReagent("minecraft:ghast_tear")
.permanentFor("mna:fey");

mna:shapes

Register with StartupEvents.registry("mna:shapes", ...).

Use it for custom spell target selection logic.

Notable builder methods:

  • guiIcon(MnaTexture)
  • initialComplexity(float)
  • spawnsTargetEntity(boolean)
  • isChanneled(boolean)
  • baselineCooldown(int)
  • affectsCaster(boolean)
  • addReagent(MnaItemId, ...)
  • target((source, level, modificationData, recipe) => SpellTarget[])
  • targetNPCCast(...)
  • allowChanneledComponents(...)
  • maxChannelTime(...)

Example:

StartupEvents.registry("mna:shapes", (event) => {
event
.create("kubejs:anchored_burst", "basic")
.guiIcon("mna:textures/gui/cantrips/ward.png")
.initialComplexity(1.5)
.spawnsTargetEntity(false)
.isChanneled(false)
.affectsCaster(true)
.target((source, level, modificationData, recipe) => {
return [SpellTarget.NONE];
});
});

mna:modifiers

Register with StartupEvents.registry("mna:modifiers", ...).

Use it for custom spell modifiers with explicit attribute coverage and craftability checks.

Notable builder methods:

  • basedOn(Modifier)
  • guiIcon(MnaTexture)
  • attributes(Attribute...)
  • addAttribute(Attribute)
  • requiredXPForRote(int)
  • tier(int)
  • isUseableByPlayers(boolean)
  • isCraftable(...)
  • canBeCastAt(...)

Example:

StartupEvents.registry("mna:modifiers", (event) => {
/**
* @type {Internal.CustomModifier$Builder}
*/
const builder = event.create("kubejs:steady_focus", "basic");
builder
.guiIcon("mna:textures/gui/cantrips/ignite.png")
.attributes(Attribute.RANGE, Attribute.PRECISION)
.tier(1)
.requiredXPForRote(75);
});

mna:construct_task

Register with StartupEvents.registry("mna:construct_task", ...).

Current support depth is for task metadata plus reuse of an existing AI implementation.

Notable builder methods:

  • basedOn(ConstructTask)
  • icon(MnaTexture)
  • aiTask(ConstructTask)
  • outputs(int)
  • lodestarAssignable(boolean)
  • lowTierAssignable(boolean)
  • condition(boolean)

Example:

StartupEvents.registry("mna:construct_task", (event) => {
/**
* @type {Internal.CustomConstructTask$Builder}
*/
const builder = event.create("kubejs:scripted_wait", "basic");
builder
.basedOn(MnaConstructTasks.WAIT)
.icon("mna:textures/gui/cantrips/ignite.png")
.outputs(2)
.lowTierAssignable(true);
});

Notes:

  • You can reuse an existing AI class from another task.
  • A brand-new JS-authored ConstructAITask implementation is not currently exposed as a first-class script surface.

mnajs:construct_material

Register with StartupEvents.registry("mnajs:construct_material", ...).

This is the custom construct material registry added by MnaJS.

Notable builder methods:

  • basedOn(MnaConstructMaterialId)
  • texture(MnaTexture)
  • health(int)
  • speed(float)
  • knockbackResistance(float)
  • explosionResistance(float)
  • equivalentTier(Tier)
  • cooldownMultiplier("cast_spell", float)
  • armorBonus("head", int)
  • toughnessBonus("torso", int)
  • damageBonus(float)
  • rangedDamageBonus(float)
  • rangedManaCost(float)
  • manaStorage(int)
  • intelligenceBonus(int)
  • backpackCapacityBoost(int)
  • castingTierEquivalent(int)
  • deathLoot(...)
  • modelSet(String)
  • headModels(...)
  • torsoModels(...)
  • legModels(...)
  • armModels(...)

Example:

StartupEvents.registry("mnajs:construct_material", (event) => {
/**
* @type {Internal.CustomConstructMaterial$Builder}
*/
const builder = event.create("kubejs:moonsteel", "basic");
builder
.basedOn("mna:iron")
.texture("mna:textures/entity/animated_construct/armor_iron.png")
.modelSet("iron")
.health(5)
.damageBonus(2.0)
.manaStorage(750)
.cooldownMultiplier("cast_spell", 0.85)
.armorBonus("head", 3)
.toughnessBonus("torso", 1);
});

Notes:

  • ConstructSlot and ConstructCapability can be passed as typed ids or stable lower-case strings.
  • This custom registry is separate from M&A's built-in hardcoded material list, but MnaJS bridges registered materials into M&A lookup and model registration.

item type construct_part

Register with StartupEvents.registry("item", ...) and event.create(id, "construct_part").

Use it for custom construct parts that reference built-in or custom construct materials.

Notable builder methods:

  • basedOn(ItemConstructPart)
  • material(MnaConstructMaterialId)
  • slot(MnaConstructSlotId)
  • modelMutex(int)
  • stat overrides such as armor, toughness, attackDamage, manaCapacity
  • capability controls such as actionSpeed, enabledCapabilities, addCapability
  • attackSpeedModifier(int)
  • inventorySizeBonus(int)
  • backpackCapacityBoost(int)
  • allowInLoot(boolean)

Example:

StartupEvents.registry("item", (event) => {
/**
* @type {Internal.CustomConstructPartItem$Builder}
*/
const builder = event.create("kubejs:moonsteel_basic_head", "construct_part");
builder
.material("kubejs:moonsteel")
.slot("head")
.modelMutex(ConstructMutexHead.BASIC)
.armor(3)
.intelligenceBonus(10);
});

Notes:

  • A part can reference a custom material registered in the same startup load.
  • Custom material lookup is intentionally lazy, so same-pass registration is supported.
  • Prefer string ids like "head" and "cast_spell" or typed ids, not raw catch-all values.

item type mana_battery_item

Use it for mana-storage items with Curios and inventory tick hooks.

Notable builder methods:

  • maxMana(float)
  • manaPerTick(int)
  • manaPerOperation(float)
  • curiosTick((entity, index, stack) => boolean)
  • tickEffect((stack, player, level, slot, mana, selected) => boolean)
  • onUseTick((level, living, stack, remainingUseDuration) => ...)

Example:

event
.create("kubejs:reserve_battery", "mana_battery_item")
.maxMana(500)
.manaPerTick(10)
.manaPerOperation(25)
.curiosTick((entity, index, stack) => true)
.tickEffect((stack, player, level, slot, mana, selected) => {
if (selected && mana >= 25) {
PlayerMagic.addMana(player, 1);
return true;
}
return false;
});

item type tiered_item

Use it for script-defined mana items with faction, ire, tooltip, and player-use behavior.

Notable builder methods:

  • tier(int)
  • faction(MnaFactionId)
  • minIre(float)
  • maxIre(float)
  • sneakBypass(boolean)
  • doesSneakBypassUse(...)
  • appendHoverText(...)
  • usedByPlayer(...)

Example:

event
.create("kubejs:court_signet", "tiered_item")
.tier(2)
.faction("mna:council")
.minIre(0.0)
.maxIre(0.02)
.sneakBypass(true)
.usedByPlayer((player) => {
PlayerMagic.addMana(player, 10);
});

block type spell_interactible

Use it for blocks that react when struck by an M&A spell.

Notable builder method:

  • onHitBySpell((level, pos, spell) => boolean)

Example:

event
.create("kubejs:spell_echo_anchor", "spell_interactible")
.onHitBySpell((level, pos, spell) => true);

block type manaweave_notifiable

Use it for blocks that receive manaweave pattern notifications.

Notable builder method:

  • onNotify((level, pos, state, patterns, caster) => boolean)

Example:

event
.create("kubejs:manaweave_listener", "manaweave_notifiable")
.onNotify((level, pos, state, patterns, caster) => {
return patterns != null && !patterns.isEmpty();
});