LogoKubeJS PMMO

Config Events

These hooks let you adjust PMMO configuration from server_scripts/ using JavaScript instead of editing TOML files by hand.

Setting a clean baseline

Before KubeJS config events run, PmmoJS can wipe PMMO's built-in defaults through the Forge common config file at config/pmmojs-common.toml:

[disableDefaultSettings]
all = false
skills = false
perks = false
requirements = false
xpAwards = false
itemExtras = false
blockVeinData = false

The execution order guarantees your scripts always win:

  1. PmmoJS reads pmmojs-common.toml
  2. Enabled categories clear PMMO's defaults
  3. Your PmmoJS.skillsConfig and PmmoJS.settings calls apply your custom data

PmmoJS.skillsConfig

Add, replace, or remove PMMO skills.

PmmoJS.skillsConfig(event => {
event
.addSkill('defense')
.withColor(0x2f6fed)
.withMaxLevel(100)
.withIconSize(18)
.build()
event.removeDefaultSkill('swimming')
})

If you remove and re-add the same skill in one pass, your custom definition wins.

PmmoJS.perksConfig

Edit existing PMMO perk entries. Use this to configure perk settings that PMMO ships with or that you registered during startup.

PmmoJS.perksConfig(event => {
event.clearPerks(EventType.SKILL_UP) // wipe all SKILL_UP perks
event.removePerkType('pmmo:fireworks') // remove a specific perk by ID
})

Core methods:

  • addPerk(eventType, perkId, skill) — add a new perk entry
  • clearPerks(eventType) — delete all perks for an event type
  • removePerkType(perkId) — delete every entry with a matching perk ID
  • removePerk(tag) — delete entries matching both perk ID and skill

After calling addPerk(...), you can chain builder methods to configure the perk entry:

MethodKey written
withCooldown(ticks)cooldown
withChance(value)chance
withMinLevel(level)min_level
withMaxLevel(level)max_level
withPerXLevel(step)per_x_level
withMilestones(values)milestones
withString(key, value), withBool(key, value), withInt(key, value), etc.Custom scalar keys

Specialized perk builders

PMMO has several built-in perk types. PmmoJS provides dedicated builder methods for each:

Builder methodWhat it configuresNotable keys
asAttributePerk()Permanent attribute bonusattribute, multiplicative, max_boost, per_level, base
asTempAttributePerk()Temporary attribute bonusSame as above + duration
asDamageBoostPerk()Bonus damageapplies_to, for_damage + boost keys
asDamageReducePerk()Damage resistancefor_damage + boost keys
asBreakSpeedPerk()Mining speedpickaxe_dig, axe_dig, shovel_dig, etc.
asEffectPerk()Potion effecteffect, duration, modifier, ambient, visible
asCommandPerk()Run a commandcommand, function
asFireworksPerk()Fireworks displaycolors
asJumpBoostPerk()Jump height bonusmax_boost, per_level, base
asBreathPerk()Breath time bonusmax_boost, per_level, base
asVillagerBoostPerk()Villager trade bonusmax_boost, per_level, base
asTameBoostPerk()Taming bonusmax_boost, per_level, base

Full example with a dedicated builder:

PmmoJS.perksConfig(event => {
event
.addPerk(EventType.SKILL_UP, 'pmmo:attribute', 'endurance')
.asAttributePerk()
.withAttribute(Java.loadClass('net.minecraft.world.entity.ai.attributes.Attributes').MAX_HEALTH)
.withPerLevel(1)
.withMaxBoost(10)
.build()
})

PmmoJS.serverConfig

Adjust PMMO's server-level settings.

PmmoJS.serverConfig(event => {
event
.setMaxLevel(100)
.setGlobalModifier(1.0)
.setUseExponentialFormula(true)
.setTreasureEnabled(true)
event.addSkillModifier('defense', 1.1)
event.addJumpXp('agility', 0.5)
event.addPartyBonus('charisma', 0.1)
})

PmmoJS.autoValueConfig

Override how PMMO generates values for blocks and items automatically.

PmmoJS.autoValueConfig(event => {
event
.setAutoValuesEnabled(true)
.setRaritiesModifier(1.5)
.setHardnessModifier(2.0)
event.addItemXpAward(EventType.CRAFT, 'smithing', 25)
event.addBlockReq(ReqType.BREAK, 'mining', 5)
event.setAxeOverride({
woodcutting: 15,
})
})

PmmoJS.antiCheeseConfig

Configure AFK detection, diminishing returns, and XP normalization.

PmmoJS.antiCheeseConfig(event => {
event.setAfkCanSubtract(false)
event
.addAfkSetting(EventType.BLOCK_BREAK)
.minTime(600)
.reduction(0.1)
.cooloff(5)
.tolerance(3.0)
.strictTolerance(true)
.build()
})

PmmoJS.globalsConfig

Manage PMMO's global NBT path aliases and comparator aliases.

PmmoJS.globalsConfig(event => {
event.addPath('durability', 'Damage')
event.addConstant('iron_material', 'tconstruct:iron')
event.removePath('old_path')
event.removeConstant('OLD_CONSTANT')
})

PMMO only reads these globals while evaluating NBT logic. They do not change normal requirements, normal XP awards, server modifiers, skill caps, or perk config.

How PMMO uses globals

In PMMO 1.20.1, NBT logic evaluates each case in this order:

  1. For every configured path, PMMO expands #alias through GlobalsConfig.PATHS.
  2. PMMO reads values from the item's, block's, or entity's NBT with the expanded path.
  3. For every comparator, PMMO expands #alias through GlobalsConfig.CONSTANTS.
  4. PMMO compares the NBT value against the expanded comparator.
  5. If the comparison passes, PMMO applies the skill map on that criteria.

That means globals are shorthand. They are not variables in every PMMO config field. Use them in NBT paths and NBT comparators.

PmmoJS.globalsConfig(event => {
event.addPath('head_material', 'tic_materials[0]')
event.addConstant('manyullyn', 'tconstruct:manyullyn')
})
PmmoJS.settings(event => {
event
.item('tconstruct:pickaxe')
.override(true)
.nbtRequirement(ReqType.TOOL)
.newCase('#head_material')
.equals('#manyullyn', 'mining', 35)
.done()
})

At runtime, PMMO reads tic_materials[0] from the pickaxe NBT and compares it to tconstruct:manyullyn.

Composite NBT example

The main reason to use globals is to make long NBT rules readable across many objects. This example combines three ideas:

  • A base requirement on the item ID.
  • An additive NBT requirement for every material part.
  • A damage-based discount when the tool is heavily worn.
const BehaviorToPrevious = Java.loadClass('harmonised.pmmo.core.nbt.BehaviorToPrevious')
PmmoJS.globalsConfig(event => {
event.addPath('all_tic_materials', 'tic_materials[]')
event.addPath('damage', 'Damage')
event.addConstant('wood', 'tconstruct:wood')
event.addConstant('iron', 'tconstruct:iron')
event.addConstant('manyullyn', 'tconstruct:manyullyn')
})
PmmoJS.settings(event => {
event
.item('tconstruct:pickaxe')
.override(true)
.setRequirement(ReqType.TOOL, 'mining', 5)
.nbtRequirement(ReqType.TOOL)
.additive(true)
.newCase('#all_tic_materials')
.equals('#wood', 'mining', 1)
.equals('#iron', 'mining', 5)
.equals('#manyullyn', 'mining', 20)
.done()
.nbtRequirement(ReqType.TOOL)
.behavior(BehaviorToPrevious.SUB_FROM)
.newCase('#damage')
.greaterThan(800, 'mining', 10)
.done()
})

The first NBT entry can add several material contributions because tic_materials[] reads every list entry and .additive(true) makes matching cases add together. The second NBT entry subtracts 10 mining requirement when Damage is greater than 800.

See PMMO Authoring Workflow for how globals fit with skills, object settings, perks, and runtime hooks.

These config hooks are applied through the server reload path, so they stay compatible with PMMO config reloads and EMI tag synchronization.