---
title: Config Events
hide_meta: true
---

# 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`:

```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.

```js
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.

```js
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:

| 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:

```js
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.

```js
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.

```js
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.

```js
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.

```js
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`.

```js
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.

```js
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](../pmmo-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.
