业务模块写在 sfmc-modules,经 link / install 落到主仓 modules/packages/<folder>/,再组装进行为包。
| 仓 | 角色 |
|---|---|
ScriptsForMinecraftServer |
平台(SDK、db-server、sfmc CLI、BP 组装) |
sfmc-modules |
业务模块源码(与主仓同级放置最省事) |
# 主仓
cd ScriptsForMinecraftServer
npm install && npm run build --workspaces --if-present
# 模块仓(同级)
cd ../sfmc-modules
npm install # workspaces + 自动 junction 到主仓 SDK
npm run typecheck非同级时设置:
# PowerShell
$env:SFMC_PLATFORM_ROOT = "D:\path\to\ScriptsForMinecraftServer"
$env:SFMC_MODULES_ROOT = "D:\path\to\sfmc-modules"sfmc CLI 也会把探测到的模块根写入 configs/runtime.json#sfmc_modules_root。
| 层 | 规则 | 示例 |
|---|---|---|
| 文件夹 / install id | 短名 kebab,禁止 feature-/core- 前缀 |
land、my-mod、area |
| npm | @sfmc-bds/module-<folder>(与平台同组织) |
@sfmc-bds/module-land |
| manifest.id | feature-<folder> 或 core-<folder> |
feature-land |
| configKey | folder 的 - → _ |
land、my_mod、online_time |
若 IDE 仍报找不到
sdk/@sfmc-sdk/tsconfig.json,确认sapi/tsconfig.json的extends为../../../tsconfig.base.json,然后执行 TypeScript: Restart TS Server。
flowchart LR
A[sfmc-modules 改代码] --> B[sfmc reload]
B --> C[build + deploy]
C --> D[向 BDS 发 reload]
D --> E[游戏内验证]
sfmc module create # 问 id/名称 → 写到 sfmc-modules → 可选 link / enable / build
sfmc module link # 从 packages/* 选择并 --link
sfmc module link land # 非交互 link
sfmc module dev # link + enable + build + deploysfmc reload # = pack build + deploy + 向 BDS 发送 reload
sfmc reload --build-only # 只部署;随后在 BDS/游戏内手动输入 reloadreload 语义(重要):
- 把新
main.js部署到世界行为包目录 - 向 BDS 控制台发送命令
reload(不是restart bds) - BDS / 游戏内也可自行输入
reload
改 configs/*.json 仍需重启对应进程(SAPI 配置启动时缓存);那是配置问题,与模块代码 reload 不同。
sfmc mod link land
# 或
sfmc mod install land --from dir:../sfmc-modules/packages/land --link
sfmc pack build && sfmc pack deploy
# 然后: send bds reload 或在游戏内 / BDS 控制台输入 reload底层脚本:
node tools/new-module.mjs my-mod --name "我的模块" --root ../sfmc-modules
node tools/fetch-module.mjs install land --from dir:../sfmc-modules/packages/land --link--link 使用 Windows junction / POSIX symlink,改 sfmc-modules 源码即反映到主仓 packages,不必反复拷贝。发布给服务器时用默认 copy 安装,不要用 --link。
packages/land/
├── package.json # @sfmc-bds/module-land
├── sapi/
│ ├── manifest.json # id: feature-land
│ ├── tsconfig.json
│ └── src/
│ ├── index.ts # ModuleRegistry.register
│ ├── types.ts # 本模块权威类型(可选)
│ └── client.ts # 对外简洁 API(有 provides 时推荐)
└── resource_pack/ # 可选
模块配置缺省由首次写入 configs/<configKey>.json 或模块代码内默认提供(平台不再播种 configs-default/)。
import { ModuleRegistry } from "@sfmc-bds/sdk/module-loader";
import { Permission, Command } from "@sfmc-bds/sdk/sapi/runtime";
ModuleRegistry.register({
id: "feature-afk",
afterWorldLoad: false,
lifecycle: {
registerPermissions() {
Permission.register("afk.use", Permission.Any);
},
registerCommands() {
Command.register("afk", "afk.use", (player) => { /* … */ }, "AFK");
},
async init() { /* db / config / service */ },
cleanup() {},
},
});| 导入 | 用途 |
|---|---|
@sfmc-bds/sdk/sapi/runtime |
消息、命令、权限、菜单、Money(余额缓存) |
@sfmc-bds/sdk/sapi/db |
表定义、CRUD、事务 |
@sfmc-bds/sdk/sapi/config |
模块配置读写 |
@sfmc-bds/sdk/sapi/service |
调其它模块的 service(无 typed client 时) |
- 不要 import 其它模块业务源码;不要直接读写对方私有表(如
sfmc_economy_*)。 - 优先用对方提供的 typed client(例:
@sfmc-bds/module-economy/client)。 - 无 client 时用
service.get("name", input);在db.tx内用tx.call/economy.account.inTx(tx)。 package.json声明对@sfmc-bds/module-*的依赖;manifest.requires/services.requires声明运行时依赖。- 玩家消息用
Msg.*,别直接player.sendMessage()。
import { economy } from "@sfmc-bds/module-economy/client";
await economy.account.get({ playerId });
await db.tx(async (tx) => {
await economy.account.inTx(tx).debit({ playerId, amount: 10, reason: "buy" });
});以主仓 / sfmc-modules 仓库根 devDependencies + 主仓 overrides 为权威 pin。
业务模块 不要 在 package.json 里声明 @minecraft/*(含 peerDependencies);类型由 workspace 根提升提供。校验:
node tools/check-minecraft-versions.mjs详见 sfmc-modules CONTRIBUTING.md。
使用 @sfmc-bds/eslint-plugin(仓库路径 modules/sdk/@sfmc-eslint-plugin/,形态对齐 Minecraft 官方 lint 插件):
| 规则 | 默认 | 说明 |
|---|---|---|
@sfmc-bds/no-player-send-message |
warn | 用 Msg.*,勿 sendMessage |
@sfmc-bds/no-sfmc-sdk-alias |
error | 用 @sfmc-bds/sdk,勿 @sfmc/sdk |
@sfmc-bds/no-sdk-deep-import |
error | 勿相对路径深挖 SDK 源码 |
@sfmc-bds/no-sdk-private-export |
error | 仅允许 SDK 公开 exports 子路径 |
@sfmc-bds/require-module-registry |
warn | sapi/src/index.ts 须 ModuleRegistry.register |
@sfmc-bds/no-db-toplevel-in-tx |
error | db.tx 内用 tx.* / tx.call,勿顶层 db.* / service.get |
@sfmc-bds/require-command-permission |
warn | Command.register 字符串权限须同包 Permission.register |
@sfmc-bds/no-httpdb-legacy |
warn | 勿用 HttpDB;改用 db / service / config |
@sfmc-bds/require-service-requires |
warn | service.get / tx.call 须声明 services.requires |
@sfmc-bds/valid-config-key |
warn | config.get/set 字段对照默认配置 |
@sfmc-bds/require-await-sdk-promise |
warn | SDK 异步 API 须 await |
@sfmc-bds/no-economy-private-tables |
error | 勿读写 sfmc_economy_*;用 economy client |
@sfmc-bds/no-platform-internal-import |
error | 勿 import 平台内部(db-server / sfmc / …) |
@sfmc-bds/no-cross-module-source-import |
error | 勿深挖其它模块源码;用公开 client |
# 主仓:SDK 源码(Msg 实现处已关闭 no-player-send-message)
npm run lint
# sfmc-modules:packages/*/sapi/src
cd ../sfmc-modules && npm run lint更严预设:sfmc.configs.all(见插件 README)。
- sfmc-modules 打 GitHub Release,更新
index.json - 主仓
sfmc mod install land(默认 copy) sfmc mod enable …→sfmc reload(或start bds触发装载闸门)
契约字段见 manifest。