---
title: 内部钩子
hide_meta: true
---

# 内部钩子

`PmmoJS.internal` 覆盖不经过触发器注册表的 PMMO 处理器路径。当你需要直接拦截 PMMO 的内置处理器逻辑时，使用这些钩子。

## 何时用 internal vs trigger

当你想挂接的处理器无法通过 `PmmoJS.trigger` 访问时，使用 `PmmoJS.internal`。通用规则：

- **`PmmoJS.trigger`** —— 经过 `EventTriggerRegistry` 路由的 PMMO 事件。大多数游戏操作都在这里：破坏方块、合成、战斗、移动等。
- **`PmmoJS.internal`** —— 从未使用触发器注册表的 PMMO 处理器类。这些是特定的引擎级路径：登录、跨维度、爆炸、活塞、玩家死亡、睡觉、药水酿造。

## 支持的内部钩子

在 PMMO 1.7.40 上，以下内部钩子已被桥接：

| 钩子 ID | 拦截内容 |
|---|---|
| `DIMENSION_TRAVEL` | 玩家切换维度 |
| `EXPLOSION` | 爆炸事件（注入受影响的方块/实体计数） |
| `LOGIN` | 玩家登录和数据同步 |
| `MOUNT` | 玩家骑乘实体 |
| `PISTON` | 活塞区块追踪更新 |
| `PLAYER_DEATH` | 玩家死亡经验损失处理 |
| `POTION_BREW` | 药水酿造（也可通过 `EventType.BREW` 访问） |
| `SLEEP_FINISHED` | 玩家完成睡觉 |

## 两条控制路径

`PMMOInternalEventJS` 给你两种独立控制 PMMO 行为的方式：

- **仅跳过 PMMO：** `event.skipPmmo()` 或 `event.setSkipPmmo(true)` —— PMMO 的处理器逻辑被跳过，但底层 Forge 动作不会被取消。当你希望 PMMO 忽略该事件，但游戏其余部分正常处理时使用。
- **拒绝动作：** `event.deny()` 或 `event.setActionCancelled(true)` —— 取消被包装的 Forge 动作并跳过 PMMO 的处理器。当你想完全阻止该动作时使用。

```js
PmmoJS.internal(PMMOInternalType.DIMENSION_TRAVEL, event => {
    const player = event.getPlayer()
    if (!player) return

    if (player.stages.has('pmmo_bypass_travel')) {
        event.skipPmmo()  // 允许玩家传送，只是不运行 PMMO 的检查
    }

    if (player.stages.has('pmmo_lock_dimensions')) {
        event.deny()  // 完全阻止传送
    }
})
```

## 药水酿造示例

`POTION_BREW` 比较特殊：桥接层向上下文注入一个追踪标记，并让你控制酿造物品的输出。

```js
PmmoJS.internal(PMMOInternalType.POTION_BREW, event => {
    if (event.getContextBoolean('alreadyTracked')) {
        return
    }

    event.addXpAward('alchemy', 10)
    event.putContextBoolean('markBrewed', true)
})
```

## 爆炸示例

`EXPLOSION` 会从桥接层接收 `affectedBlockCount` 和 `affectedEntityCount`：

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

## 内部事件的关键方法

- `getType()` 和 `getTypeId()` —— 触发的是哪个内部钩子
- `getForgeEvent()` 和 `getForgeEventClassName()` —— 底层的 Forge 事件
- `hasPlayer()`、`getPlayer()`、`getServerPlayer()` —— 相关玩家（如果适用）
- `shouldSkipPmmo()`、`setSkipPmmo(true)`、`skipPmmo()` —— 跳过 PMMO 的处理器
- `canCancelAction()`、`isActionCancelled()`、`setActionCancelled(true)`、`deny()` —— 取消 Forge 动作
- `getContextBoolean(key)`、`getContextString(key)` 等 —— 读取上下文值
- `putContextBoolean(key, value)`、`putContextString(key, value)` 等 —— 写入上下文值
- `getXpAwards()`、`setXpAwards(map)`、`setXpAward(skill, amount)`、`addXpAward(skill, amount)` —— XP 管理

## ProbeJS 类型补全

PmmoJS 同时为 v6 和 v7（Legacy）ProbeJS API 提供 ProbeJS 支持。所有枚举值、事件对象和工具类的类型补全都会在 ProbeJS 生成类型定义时自动提供。

你不需要为 PmmoJS 类型编写自定义的 ProbeJS 事件监听器 —— 它们会在模组初始化时由插件注册。

对于 VSCode 用户，ProbeJS Legacy 插件还提供代码片段（例如输入 `@pmmo_internal` 获取脚手架式的内部处理器代码）。
