LogoKubeJS PMMO

Internal Hooks

PmmoJS.internal covers PMMO handler paths that do not go through the trigger registry. Use these hooks when you need to intercept PMMO's built-in handler logic directly.

When to use internal vs trigger

Use PmmoJS.internal when the handler you want to hook into is not available through PmmoJS.trigger. The general rule:

  • PmmoJS.trigger — PMMO events that route through the EventTriggerRegistry. Most gameplay actions live here: breaking blocks, crafting, combat, movement, etc.
  • PmmoJS.internal — PMMO handler classes that never use the trigger registry. These are specific engine-level paths: login, dimension travel, explosions, pistons, player death, sleep, potion brewing.

Supported internal hooks

On PMMO 1.7.40, the following internal hooks are bridged:

Hook IDWhat it intercepts
DIMENSION_TRAVELPlayer changing dimensions
EXPLOSIONExplosion events (seeded with affected block/entity counts)
LOGINPlayer login and data sync
MOUNTPlayer mounting an entity
PISTONPiston chunk tracking updates
PLAYER_DEATHPlayer death XP loss handling
POTION_BREWPotion brewing (also reachable via EventType.BREW)
SLEEP_FINISHEDPlayer finishing sleep

Two control paths

PMMOInternalEventJS gives you two independent ways to control PMMO's behavior:

  • Skip PMMO only: event.skipPmmo() or event.setSkipPmmo(true) — PMMO's handler logic is skipped, but the underlying Forge action is not cancelled. Use this when you want PMMO to ignore the event while the rest of the game processes it normally.
  • Deny the action: event.deny() or event.setActionCancelled(true) — Cancels the wrapped Forge action AND skips PMMO's handler. Use this when you want to prevent the action entirely.
PmmoJS.internal(PMMOInternalType.DIMENSION_TRAVEL, event => {
const player = event.getPlayer()
if (!player) return
if (player.stages.has('pmmo_bypass_travel')) {
event.skipPmmo() // let the player travel, just don't run PMMO's checks
}
if (player.stages.has('pmmo_lock_dimensions')) {
event.deny() // block the travel entirely
}
})

Potion brewing example

POTION_BREW is special: the bridge seeds the context with a tracking flag and lets you control the brewed-item output.

PmmoJS.internal(PMMOInternalType.POTION_BREW, event => {
if (event.getContextBoolean('alreadyTracked')) {
return
}
event.addXpAward('alchemy', 10)
event.putContextBoolean('markBrewed', true)
})

Explosion example

EXPLOSION receives affectedBlockCount and affectedEntityCount from the bridge:

PmmoJS.internal(PMMOInternalType.EXPLOSION, event => {
if (event.getContextInt('affectedBlockCount') > 64) {
event.setSkipPmmo(true)
}
})

Key methods on the internal event

  • getType() and getTypeId() — which internal hook fired
  • getForgeEvent() and getForgeEventClassName() — the underlying Forge event
  • hasPlayer(), getPlayer(), getServerPlayer() — the player, if applicable
  • shouldSkipPmmo(), setSkipPmmo(true), skipPmmo() — skip PMMO's handler
  • canCancelAction(), isActionCancelled(), setActionCancelled(true), deny() — cancel the Forge action
  • getContextBoolean(key), getContextString(key), etc. — read context values
  • putContextBoolean(key, value), putContextString(key, value), etc. — write context values
  • getXpAwards(), setXpAwards(map), setXpAward(skill, amount), addXpAward(skill, amount) — XP management

ProbeJS 类型补全

PmmoJS 支持 ProbeJS 和 ProbeJS Legacy。ProbeJS 生成类型定义时,会同时生成枚举值、事件对象和工具类的类型补全。

PmmoJS 类型不需要额外编写 ProbeJS event listener;插件会在 mod 初始化时完成注册。