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 = falseskills = falseperks = falserequirements = falsexpAwards = falseitemExtras = falseblockVeinData = false
The execution order guarantees your scripts always win:
- PmmoJS reads
pmmojs-common.toml - Enabled categories clear PMMO's defaults
- Your
PmmoJS.skillsConfigandPmmoJS.settingscalls 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 perksevent.removePerkType('pmmo:fireworks') // remove a specific perk by ID})
Core methods:
addPerk(eventType, perkId, skill)— add a new perk entryclearPerks(eventType)— delete all perks for an event typeremovePerkType(perkId)— delete every entry with a matching perk IDremovePerk(tag)— delete entries matching both perk ID and skill
After calling addPerk(...), you can chain builder methods to configure the perk entry:
| Method | Key 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 method | What it configures | Notable keys |
|---|---|---|
asAttributePerk() | Permanent attribute bonus | attribute, multiplicative, max_boost, per_level, base |
asTempAttributePerk() | Temporary attribute bonus | Same as above + duration |
asDamageBoostPerk() | Bonus damage | applies_to, for_damage + boost keys |
asDamageReducePerk() | Damage resistance | for_damage + boost keys |
asBreakSpeedPerk() | Mining speed | pickaxe_dig, axe_dig, shovel_dig, etc. |
asEffectPerk() | Potion effect | effect, duration, modifier, ambient, visible |
asCommandPerk() | Run a command | command, function |
asFireworksPerk() | Fireworks display | colors |
asJumpBoostPerk() | Jump height bonus | max_boost, per_level, base |
asBreathPerk() | Breath time bonus | max_boost, per_level, base |
asVillagerBoostPerk() | Villager trade bonus | max_boost, per_level, base |
asTameBoostPerk() | Taming bonus | max_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:
- For every configured path, PMMO expands
#aliasthroughGlobalsConfig.PATHS. - PMMO reads values from the item's, block's, or entity's NBT with the expanded path.
- For every comparator, PMMO expands
#aliasthroughGlobalsConfig.CONSTANTS. - PMMO compares the NBT value against the expanded comparator.
- 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.