---
title: 启动阶段规则
hide_meta: true
---

# 启动阶段规则

这一页回答一个问题：**每种 PmmoJS 代码应该放在哪个脚本文件夹？**

## 规则

对于带 KubeJS 的 Forge 1.20.1：

| 脚本文件夹 | 用途 |
|---|---|
| `startup_scripts/` | 注册和仅限启动的 Forge 钩子 |
| `server_scripts/` | PMMO 运行时逻辑和 ProbeJS 文档生成 |
| `client_scripts/` | 只读技能显示辅助和客户端 UI |

## 实操指南

### `startup_scripts/`

用于在游戏世界加载之前定义数据的任何内容：

```js
// 谓词
PmmoJS.registerPredicate(event => {
  event.registerActionPredicate(PmmoHelper.id('minecraft:stick'), ReqType.WEAPON,
    (player, stack) => player.experienceLevel >= 5
  )
})

// 直接数据注册
PmmoHelper.registerXpAwardData(ObjectType.ITEM, 'minecraft:bread', EventType.CONSUME, {
  cooking: 2
}, true)

// 原始 Forge 事件
ForgeEvents.onEvent('net.minecraftforge.event.entity.player.PlayerEvent$PlayerLoggedInEvent', event => {
  console.info(`[PmmoJS] ${event.getEntity().getScoreboardName()} 已登录`)
})
```

### `server_scripts/`

用于游戏反应、配置编辑和文档生成：

```js
// 运行时触发器
PmmoJS.trigger(EventType.BLOCK_BREAK, event => {
  if (event.hasPlayer()) {
    event.addXpAward('mining', 5)
  }
})

// 内部钩子
PmmoJS.internal(PMMOInternalType.POTION_BREW, event => {
  if (!event.getContextBoolean('alreadyTracked')) {
    event.addXpAward('alchemy', 10)
  }
})

// ProbeJS 文档生成
ProbeJSEvents.generateDoc(event => {
  event.addSnippet('pmmojs.trigger.type', PmmoHelper.getTriggerTypeIds(), 'PmmoJS 触发器 ID')
})
```

### `client_scripts/`

仅限只读操作。`SkillHelper` 和 `ClientSkillHelper` 可用于技能显示查询。`PmmoHelper` 在客户端不暴露。

## 常见错误

- **把 `ForgeEvents.onEvent(...)` 放在 `server_scripts/` 中** —— 在 KubeJS 1.20.1 上，这是启动 API。在服务端脚本中不起作用。
- **把 `ProbeJSEvents.generateDoc(...)` 放在 `startup_scripts/` 中** —— 这是服务端 API。在启动脚本中不起作用。
- **把 `PmmoJS.registerPerk(...)` 放在 `server_scripts/` 中** —— 这需要在注册时间运行，而不是在游戏过程中。移到启动脚本中。

## 重载行为

- 启动脚本只在模组初始化期间运行一次，不支持热重载。
- 服务端脚本在每次服务器重载时运行，这是你迭代游戏逻辑的地方。
- 服务端脚本中的配置事件通过重载路径应用，因此与 PMMO 自身的配置重载兼容。

## 决策流程

问问自己代码在做什么：

- **在加载时定义数据或结构？** → `startup_scripts/`
- **响应游戏行为或编辑配置？** → `server_scripts/`
- **只读取技能数据用于 UI 显示？** → `client_scripts/`
- **生成 ProbeJS 类型文档？** → `server_scripts/`
