@sfmc-bds/bds-tools 0.1.0 → 0.2.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bds-manager.d.ts.map +1 -1
- package/dist/bds-manager.js +236 -263
- package/dist/bds-manager.js.map +7 -1
- package/dist/changelog.js +39 -50
- package/dist/changelog.js.map +7 -1
- package/dist/check-update.d.ts +2 -2
- package/dist/check-update.d.ts.map +1 -1
- package/dist/check-update.js +361 -401
- package/dist/check-update.js.map +7 -1
- package/dist/cli-pack-manager.d.ts +10 -6
- package/dist/cli-pack-manager.d.ts.map +1 -1
- package/dist/cli-pack-manager.js +226 -135
- package/dist/cli-pack-manager.js.map +7 -1
- package/dist/fsx.js +86 -100
- package/dist/fsx.js.map +7 -1
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +166 -185
- package/dist/http.js.map +7 -1
- package/dist/is-main.d.ts +17 -0
- package/dist/is-main.d.ts.map +1 -0
- package/dist/is-main.js +32 -0
- package/dist/is-main.js.map +7 -0
- package/dist/log.d.ts +2 -4
- package/dist/log.d.ts.map +1 -1
- package/dist/log.js +12 -19
- package/dist/log.js.map +7 -1
- package/dist/logger.js +6 -10
- package/dist/logger.js.map +7 -1
- package/dist/pack-manager.d.ts +88 -24
- package/dist/pack-manager.d.ts.map +1 -1
- package/dist/pack-manager.js +280 -245
- package/dist/pack-manager.js.map +7 -1
- package/dist/paths.d.ts +8 -3
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +53 -39
- package/dist/paths.js.map +7 -1
- package/dist/qqutil.d.ts.map +1 -1
- package/dist/qqutil.js +90 -87
- package/dist/qqutil.js.map +7 -1
- package/dist/recovery.js +26 -37
- package/dist/recovery.js.map +7 -1
- package/dist/rollback.d.ts +1 -1
- package/dist/rollback.js +55 -74
- package/dist/rollback.js.map +7 -1
- package/dist/server-properties.d.ts +12 -0
- package/dist/server-properties.d.ts.map +1 -0
- package/dist/server-properties.js +28 -0
- package/dist/server-properties.js.map +7 -0
- package/dist/taskbar.d.ts +2 -0
- package/dist/taskbar.d.ts.map +1 -1
- package/dist/taskbar.js +51 -82
- package/dist/taskbar.js.map +7 -1
- package/dist/types.js +1 -5
- package/dist/types.js.map +7 -1
- package/dist/update-result.d.ts +12 -0
- package/dist/update-result.d.ts.map +1 -0
- package/dist/update-result.js +15 -0
- package/dist/update-result.js.map +7 -0
- package/dist/upstream.js +94 -108
- package/dist/upstream.js.map +7 -1
- package/dist/version.js +63 -81
- package/dist/version.js.map +7 -1
- package/dist/world-packs.d.ts +112 -0
- package/dist/world-packs.d.ts.map +1 -0
- package/dist/world-packs.js +335 -0
- package/dist/world-packs.js.map +7 -0
- package/dist/zipx.d.ts +10 -0
- package/dist/zipx.d.ts.map +1 -0
- package/dist/zipx.js +48 -0
- package/dist/zipx.js.map +7 -0
- package/package.json +17 -6
package/dist/pack-manager.js
CHANGED
|
@@ -1,264 +1,299 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* pack-manager.ts — Bedrock 行为包/资源包 装配 + 部署到 BDS 根。
|
|
3
|
-
*
|
|
4
|
-
* 这是 SEA 与 npm 两条用户路径共用的纯函数库:
|
|
5
|
-
*
|
|
6
|
-
* - SEA:用户在 REPL/wizard 里跑 `sfmc behavior-pack build/deploy`
|
|
7
|
-
* → sfmc 通过 spawnService 启 `bds-tools/dist/pack-manager.js`,
|
|
8
|
-
* SEA 自己跑 esbuild 把脚本 bundle 写到 <modulesDir>/build/sfmc-modules-bp/scripts/main.js,
|
|
9
|
-
* 然后调 pack-manager#assembleBehaviorPack 装配。
|
|
10
|
-
* - npm: 用户跑 `sfmc behavior-pack build`,
|
|
11
|
-
* 同一 spawnService 路径。或者直接在同进程 import 这个库。
|
|
12
|
-
*
|
|
13
|
-
* 关键约束:本文件不允许引 esbuild / 任何 npm-only 包 — SEA 要把它打成 SEA
|
|
14
|
-
* 的一部分内嵌起来,而 SEA 是个单 exe (除 Node 内置 + bds-tools 已有依赖外)。
|
|
15
|
-
*
|
|
16
|
-
* 已有依赖 (bds-tools/package.json):
|
|
17
|
-
* - cli-progress: 进度条
|
|
18
|
-
* - node-html-parser: changelog 抓取 (本文件用不到)
|
|
19
|
-
* - jszip: zip 解压(模块 zip / BDS server.zip),与 sfmc/wizard 共享同一个库
|
|
20
|
-
*
|
|
21
|
-
* 没有外部依赖意味着:SEA 静态把 `bds-tools/dist/*` 解压到 exe 旁边即可,
|
|
22
|
-
*不需把 npm 整棵树带进去。
|
|
23
|
-
*/
|
|
24
1
|
import fs from "node:fs";
|
|
25
2
|
import path from "node:path";
|
|
26
3
|
import { copyDirAsync, copyFileAsync } from "./fsx.js";
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
"@minecraft/server-editor",
|
|
36
|
-
"@minecraft/diagnostics",
|
|
4
|
+
const SFMC_PERMISSIONS = [
|
|
5
|
+
"@minecraft/server",
|
|
6
|
+
"@minecraft/server-ui",
|
|
7
|
+
"@minecraft/server-admin",
|
|
8
|
+
"@minecraft/server-gametest",
|
|
9
|
+
"@minecraft/server-net",
|
|
10
|
+
"@minecraft/server-editor",
|
|
11
|
+
"@minecraft/diagnostics"
|
|
37
12
|
];
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
/* crypto.randomUUID 是 Node 19+ 内置,SEA 走 Node 22+,这里直接用 */
|
|
41
|
-
return crypto.randomUUID();
|
|
13
|
+
function serverPropertiesPath(bdsRoot) {
|
|
14
|
+
return path.join(bdsRoot, "server.properties");
|
|
42
15
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
* Assemble a Bedrock behavior pack directory at `outDir` from a prebuilt
|
|
46
|
-
* `srcDir` (which must already contain `scripts/main.js` plus whatever else
|
|
47
|
-
* was bundled by esbuild) and write a fresh `manifest.json` + `permissions.json`.
|
|
48
|
-
*
|
|
49
|
-
* The caller is responsible for running esbuild first; pack-manager does not
|
|
50
|
-
* bundle scripts. That decoupling is what lets the SEA ship without esbuild.
|
|
51
|
-
*/
|
|
52
|
-
export async function assembleBehaviorPack(opts) {
|
|
53
|
-
const version = opts.version ?? [1, 0, 0];
|
|
54
|
-
const bpUuid = randomUuid();
|
|
55
|
-
await fs.promises.rm(opts.outDir, { recursive: true, force: true });
|
|
56
|
-
await fs.promises.mkdir(opts.outDir, { recursive: true });
|
|
57
|
-
if (fs.existsSync(opts.srcDir)) {
|
|
58
|
-
await copyDirAsync(opts.srcDir, opts.outDir);
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
await fs.promises.mkdir(path.join(opts.outDir, "scripts"), { recursive: true });
|
|
62
|
-
await fs.promises.writeFile(path.join(opts.outDir, "scripts", "main.js"), "/* no scripts */\n", "utf8");
|
|
63
|
-
}
|
|
64
|
-
await writeBehaviorPackManifest(opts.outDir, {
|
|
65
|
-
name: opts.projectName,
|
|
66
|
-
uuid: bpUuid,
|
|
67
|
-
version,
|
|
68
|
-
description: opts.description,
|
|
69
|
-
});
|
|
70
|
-
if (opts.iconSrc && fs.existsSync(opts.iconSrc)) {
|
|
71
|
-
await copyFileAsync(opts.iconSrc, path.join(opts.outDir, "pack_icon.png"));
|
|
72
|
-
}
|
|
73
|
-
await writePermissionsJson(opts.outDir);
|
|
16
|
+
function bdsWorldsDir(bdsRoot) {
|
|
17
|
+
return path.join(bdsRoot, "worlds");
|
|
74
18
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
* at `outDir`, with a single fresh `manifest.json`. Per-module subfolders are
|
|
78
|
-
* preserved so resource pack authors can disambiguate (e.g. `peace/textures/...`).
|
|
79
|
-
*/
|
|
80
|
-
export async function assembleResourcePack(opts) {
|
|
81
|
-
const version = opts.version ?? [1, 0, 0];
|
|
82
|
-
const rpUuid = randomUuid();
|
|
83
|
-
await fs.promises.rm(opts.outDir, { recursive: true, force: true });
|
|
84
|
-
await fs.promises.mkdir(opts.outDir, { recursive: true });
|
|
85
|
-
for (const [moduleId, rpDir] of Object.entries(opts.moduleResourceDirs)) {
|
|
86
|
-
if (!fs.existsSync(rpDir))
|
|
87
|
-
continue;
|
|
88
|
-
const dst = path.join(opts.outDir, moduleId);
|
|
89
|
-
await fs.promises.mkdir(dst, { recursive: true });
|
|
90
|
-
await copyDirAsync(rpDir, dst);
|
|
91
|
-
}
|
|
92
|
-
await writeResourcePackManifest(opts.outDir, {
|
|
93
|
-
name: opts.projectName,
|
|
94
|
-
uuid: rpUuid,
|
|
95
|
-
version,
|
|
96
|
-
description: opts.description,
|
|
97
|
-
});
|
|
19
|
+
function bdsWorldLevelDir(bdsRoot, levelName) {
|
|
20
|
+
return path.join(bdsWorldsDir(bdsRoot), levelName);
|
|
98
21
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
* the key is absent.
|
|
103
|
-
*/
|
|
104
|
-
export async function readLevelName(bdsRoot) {
|
|
105
|
-
const file = path.join(bdsRoot, "server.properties");
|
|
106
|
-
if (!fs.existsSync(file))
|
|
107
|
-
return "Bedrock level";
|
|
108
|
-
const text = await fs.promises.readFile(file, "utf8");
|
|
109
|
-
for (const line of text.split(/\r?\n/)) {
|
|
110
|
-
const m = /^\s*level-name\s*=\s*(.+?)\s*$/.exec(line);
|
|
111
|
-
if (m && m[1])
|
|
112
|
-
return m[1];
|
|
113
|
-
}
|
|
114
|
-
return "Bedrock level";
|
|
22
|
+
function worldPackListFile(worldsDir, levelName, kind) {
|
|
23
|
+
const name = kind === "behavior" ? "world_behavior_packs.json" : "world_resource_packs.json";
|
|
24
|
+
return path.join(worldsDir, levelName, name);
|
|
115
25
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
26
|
+
function configPermissionPath(bdsRoot, bpUuid) {
|
|
27
|
+
return path.join(bdsRoot, "config", bpUuid, "permission.json");
|
|
28
|
+
}
|
|
29
|
+
function hasConfigPermission(bdsRoot, bpUuid) {
|
|
30
|
+
return fs.existsSync(configPermissionPath(bdsRoot, bpUuid));
|
|
31
|
+
}
|
|
32
|
+
function randomUuid() {
|
|
33
|
+
return crypto.randomUUID();
|
|
34
|
+
}
|
|
35
|
+
async function assembleBehaviorPack(opts) {
|
|
36
|
+
const version = opts.version ?? [1, 0, 0];
|
|
37
|
+
const bpUuid = opts.uuid ?? randomUuid();
|
|
38
|
+
await fs.promises.rm(opts.outDir, { recursive: true, force: true });
|
|
39
|
+
await fs.promises.mkdir(opts.outDir, { recursive: true });
|
|
40
|
+
if (fs.existsSync(opts.srcDir)) {
|
|
41
|
+
await copyDirAsync(opts.srcDir, opts.outDir);
|
|
42
|
+
} else {
|
|
43
|
+
await fs.promises.mkdir(path.join(opts.outDir, "scripts"), { recursive: true });
|
|
44
|
+
await fs.promises.writeFile(path.join(opts.outDir, "scripts", "main.js"), "/* no scripts */\n", "utf8");
|
|
45
|
+
}
|
|
46
|
+
await writeBehaviorPackManifest(opts.outDir, {
|
|
47
|
+
name: opts.projectName,
|
|
48
|
+
uuid: bpUuid,
|
|
49
|
+
version,
|
|
50
|
+
description: opts.description,
|
|
51
|
+
moduleUuid: opts.moduleUuid
|
|
52
|
+
});
|
|
53
|
+
if (opts.iconSrc && fs.existsSync(opts.iconSrc)) {
|
|
54
|
+
await copyFileAsync(opts.iconSrc, path.join(opts.outDir, "pack_icon.png"));
|
|
55
|
+
}
|
|
56
|
+
await writePermissionsJson(opts.outDir);
|
|
57
|
+
return { uuid: bpUuid, version };
|
|
58
|
+
}
|
|
59
|
+
async function assembleResourcePack(opts) {
|
|
60
|
+
const version = opts.version ?? [1, 0, 0];
|
|
61
|
+
const rpUuid = opts.uuid ?? randomUuid();
|
|
62
|
+
await fs.promises.rm(opts.outDir, { recursive: true, force: true });
|
|
63
|
+
await fs.promises.mkdir(opts.outDir, { recursive: true });
|
|
64
|
+
for (const [moduleId, rpDir] of Object.entries(opts.moduleResourceDirs)) {
|
|
65
|
+
if (!fs.existsSync(rpDir)) continue;
|
|
66
|
+
const dst = path.join(opts.outDir, moduleId);
|
|
67
|
+
await fs.promises.mkdir(dst, { recursive: true });
|
|
68
|
+
await copyDirAsync(rpDir, dst);
|
|
69
|
+
}
|
|
70
|
+
await writeResourcePackManifest(opts.outDir, {
|
|
71
|
+
name: opts.projectName,
|
|
72
|
+
uuid: rpUuid,
|
|
73
|
+
version,
|
|
74
|
+
description: opts.description,
|
|
75
|
+
moduleUuid: opts.moduleUuid
|
|
76
|
+
});
|
|
77
|
+
return { uuid: rpUuid, version };
|
|
78
|
+
}
|
|
79
|
+
function parseLevelNameFromProperties(text) {
|
|
80
|
+
for (const line of text.split(/\r?\n/)) {
|
|
81
|
+
const m = /^\s*level-name\s*=\s*(.+?)\s*$/.exec(line);
|
|
82
|
+
if (m && m[1]) return m[1];
|
|
83
|
+
}
|
|
84
|
+
return "Bedrock level";
|
|
85
|
+
}
|
|
86
|
+
function readLevelNameSync(bdsRoot) {
|
|
87
|
+
const file = serverPropertiesPath(bdsRoot);
|
|
88
|
+
if (!fs.existsSync(file)) return "Bedrock level";
|
|
89
|
+
return parseLevelNameFromProperties(fs.readFileSync(file, "utf8"));
|
|
135
90
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
* `permissions.json`. Idempotent: rewrites any pre-existing file.
|
|
139
|
-
*/
|
|
140
|
-
export async function writePermissionsJson(bpDir) {
|
|
141
|
-
const payload = { allowed_modules: [...SFMC_PERMISSIONS] };
|
|
142
|
-
await fs.promises.mkdir(bpDir, { recursive: true });
|
|
143
|
-
const tmp = path.join(bpDir, `.permissions.${process.pid}.tmp`);
|
|
144
|
-
await fs.promises.writeFile(tmp, JSON.stringify(payload, null, 2) + "\n", "utf8");
|
|
145
|
-
await fs.promises.rename(tmp, path.join(bpDir, "permissions.json"));
|
|
146
|
-
void copyDirAsync;
|
|
91
|
+
async function readLevelName(bdsRoot) {
|
|
92
|
+
return readLevelNameSync(bdsRoot);
|
|
147
93
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
94
|
+
async function deployToBDS(opts) {
|
|
95
|
+
const levelDir = bdsWorldLevelDir(opts.bdsRoot, opts.levelName);
|
|
96
|
+
const bpDst = path.join(levelDir, "behavior_packs", opts.bpName);
|
|
97
|
+
const rpDst = path.join(levelDir, "resource_packs", opts.rpName ?? `${opts.bpName}-rp`);
|
|
98
|
+
await fs.promises.mkdir(levelDir, { recursive: true });
|
|
99
|
+
await fs.promises.rm(bpDst, { recursive: true, force: true });
|
|
100
|
+
await copyDirAsync(opts.behaviorPackSrc, bpDst);
|
|
101
|
+
await writePermissionsJson(bpDst);
|
|
102
|
+
let rpDir = null;
|
|
103
|
+
if (opts.resourcePackSrc && fs.existsSync(opts.resourcePackSrc)) {
|
|
104
|
+
await fs.promises.rm(rpDst, { recursive: true, force: true });
|
|
105
|
+
await copyDirAsync(opts.resourcePackSrc, rpDst);
|
|
106
|
+
rpDir = rpDst;
|
|
107
|
+
} else if (opts.clearResourcePack) {
|
|
108
|
+
await fs.promises.rm(rpDst, { recursive: true, force: true });
|
|
109
|
+
}
|
|
110
|
+
return { bpDir: bpDst, rpDir };
|
|
155
111
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
112
|
+
async function ensureConfigPermission(bdsRoot, bpUuid) {
|
|
113
|
+
const file = configPermissionPath(bdsRoot, bpUuid);
|
|
114
|
+
if (fs.existsSync(file)) return false;
|
|
115
|
+
const dir = path.dirname(file);
|
|
116
|
+
await fs.promises.mkdir(dir, { recursive: true });
|
|
117
|
+
const payload = { allowed_modules: [...SFMC_PERMISSIONS] };
|
|
118
|
+
const tmp = path.join(dir, `.permission.${process.pid}.tmp`);
|
|
119
|
+
await fs.promises.writeFile(tmp, JSON.stringify(payload, null, 2) + "\n", "utf8");
|
|
120
|
+
await fs.promises.rename(tmp, file);
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
function readPackManifestHeader(packDir) {
|
|
124
|
+
const file = path.join(packDir, "manifest.json");
|
|
125
|
+
if (!fs.existsSync(file)) return null;
|
|
126
|
+
try {
|
|
127
|
+
const raw = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
128
|
+
const uuid = raw.header?.uuid;
|
|
129
|
+
const ver = raw.header?.version;
|
|
130
|
+
if (typeof uuid !== "string" || !Array.isArray(ver) || ver.length < 3) return null;
|
|
131
|
+
const version = [Number(ver[0]), Number(ver[1]), Number(ver[2])];
|
|
132
|
+
const moduleUuid = raw.modules?.[0]?.uuid;
|
|
133
|
+
return { uuid, version, ...typeof moduleUuid === "string" ? { moduleUuid } : {} };
|
|
134
|
+
} catch {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
async function writePermissionsJson(bpDir) {
|
|
139
|
+
const payload = { allowed_modules: [...SFMC_PERMISSIONS] };
|
|
140
|
+
await fs.promises.mkdir(bpDir, { recursive: true });
|
|
141
|
+
const tmp = path.join(bpDir, `.permissions.${process.pid}.tmp`);
|
|
142
|
+
await fs.promises.writeFile(tmp, JSON.stringify(payload, null, 2) + "\n", "utf8");
|
|
143
|
+
await fs.promises.rename(tmp, path.join(bpDir, "permissions.json"));
|
|
144
|
+
}
|
|
145
|
+
async function enablePackInWorld(opts) {
|
|
146
|
+
await editWorldPackList(opts, "enable");
|
|
147
|
+
}
|
|
148
|
+
async function disablePackInWorld(opts) {
|
|
149
|
+
await editWorldPackList(opts, "disable");
|
|
159
150
|
}
|
|
160
151
|
async function editWorldPackList(opts, mode) {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
152
|
+
const file = worldPackListFile(opts.worldsDir, opts.levelName, opts.kind);
|
|
153
|
+
let entries = readWorldPackList(opts.worldsDir, opts.levelName, opts.kind);
|
|
154
|
+
const idx = entries.findIndex((e) => e.pack_id === opts.packUuid);
|
|
155
|
+
if (mode === "enable") {
|
|
156
|
+
const next = { pack_id: opts.packUuid, version: opts.version };
|
|
157
|
+
if (idx >= 0) entries[idx] = next;
|
|
158
|
+
else entries.push(next);
|
|
159
|
+
} else {
|
|
160
|
+
if (idx >= 0) entries.splice(idx, 1);
|
|
161
|
+
}
|
|
162
|
+
await fs.promises.mkdir(path.dirname(file), { recursive: true });
|
|
163
|
+
const tmp = `${file}.${process.pid}.tmp`;
|
|
164
|
+
await fs.promises.writeFile(tmp, JSON.stringify(entries, null, 2) + "\n", "utf8");
|
|
165
|
+
await fs.promises.rename(tmp, file);
|
|
166
|
+
}
|
|
167
|
+
async function writeBehaviorPackManifest(outDir, header) {
|
|
168
|
+
const manifest = {
|
|
169
|
+
format_version: 2,
|
|
170
|
+
header: {
|
|
171
|
+
name: header.name,
|
|
172
|
+
uuid: header.uuid,
|
|
173
|
+
version: header.version,
|
|
174
|
+
description: header.description ? `${header.description} (behavior pack)` : "SFMC behavior pack",
|
|
175
|
+
min_engine_version: [1, 21, 0]
|
|
176
|
+
},
|
|
177
|
+
modules: [
|
|
178
|
+
{
|
|
179
|
+
type: "script",
|
|
180
|
+
language: "javascript",
|
|
181
|
+
entry: "scripts/main.js",
|
|
182
|
+
uuid: header.moduleUuid ?? crypto.randomUUID(),
|
|
183
|
+
version: header.version
|
|
184
|
+
}
|
|
185
|
+
],
|
|
186
|
+
dependencies: [
|
|
187
|
+
{ module_name: "@minecraft/server", version: "1.18.0" }
|
|
188
|
+
]
|
|
189
|
+
};
|
|
190
|
+
const file = path.join(outDir, "manifest.json");
|
|
191
|
+
await fs.promises.mkdir(outDir, { recursive: true });
|
|
192
|
+
await fs.promises.writeFile(file, JSON.stringify(manifest, null, 2) + "\n", "utf8");
|
|
193
|
+
}
|
|
194
|
+
async function writeResourcePackManifest(outDir, header) {
|
|
195
|
+
const manifest = {
|
|
196
|
+
format_version: 2,
|
|
197
|
+
header: {
|
|
198
|
+
name: header.name,
|
|
199
|
+
uuid: header.uuid,
|
|
200
|
+
version: header.version,
|
|
201
|
+
description: header.description ? `${header.description} (resource pack)` : "SFMC resource pack",
|
|
202
|
+
min_engine_version: [1, 21, 0]
|
|
203
|
+
},
|
|
204
|
+
modules: [
|
|
205
|
+
{
|
|
206
|
+
type: "resources",
|
|
207
|
+
uuid: header.moduleUuid ?? crypto.randomUUID(),
|
|
208
|
+
version: header.version
|
|
209
|
+
}
|
|
210
|
+
]
|
|
211
|
+
};
|
|
212
|
+
const file = path.join(outDir, "manifest.json");
|
|
213
|
+
await fs.promises.mkdir(outDir, { recursive: true });
|
|
214
|
+
await fs.promises.writeFile(file, JSON.stringify(manifest, null, 2) + "\n", "utf8");
|
|
215
|
+
}
|
|
216
|
+
function scanModuleResourcePacks(modulesDir) {
|
|
217
|
+
const out = {};
|
|
218
|
+
if (!fs.existsSync(modulesDir)) return out;
|
|
219
|
+
for (const entry of fs.readdirSync(modulesDir, { withFileTypes: true })) {
|
|
220
|
+
if (!entry.isDirectory()) continue;
|
|
221
|
+
const rpDir = path.join(modulesDir, entry.name, "resource_pack");
|
|
222
|
+
if (fs.existsSync(rpDir)) {
|
|
223
|
+
out[entry.name] = rpDir;
|
|
180
224
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
225
|
+
}
|
|
226
|
+
return out;
|
|
227
|
+
}
|
|
228
|
+
function loadModuleResourcePackMap(jsonPath) {
|
|
229
|
+
const raw = JSON.parse(fs.readFileSync(jsonPath, "utf8"));
|
|
230
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
231
|
+
throw new Error(`modules-json must be an object: ${jsonPath}`);
|
|
232
|
+
}
|
|
233
|
+
const out = {};
|
|
234
|
+
for (const [id, dir] of Object.entries(raw)) {
|
|
235
|
+
if (typeof id !== "string" || !id || typeof dir !== "string" || !dir) continue;
|
|
236
|
+
const abs = path.resolve(dir);
|
|
237
|
+
if (!fs.existsSync(abs)) {
|
|
238
|
+
throw new Error(`modules-json entry missing: ${id} \u2192 ${abs}`);
|
|
184
239
|
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
await fs.promises.rename(tmp, file);
|
|
240
|
+
out[id] = abs;
|
|
241
|
+
}
|
|
242
|
+
return out;
|
|
189
243
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
],
|
|
210
|
-
dependencies: [
|
|
211
|
-
{ module_name: "@minecraft/server", version: "1.18.0" },
|
|
212
|
-
],
|
|
213
|
-
};
|
|
214
|
-
const file = path.join(outDir, "manifest.json");
|
|
215
|
-
await fs.promises.mkdir(outDir, { recursive: true });
|
|
216
|
-
await fs.promises.writeFile(file, JSON.stringify(manifest, null, 2) + "\n", "utf8");
|
|
244
|
+
function readWorldPackListResult(worldsDir, levelName, kind) {
|
|
245
|
+
const file = worldPackListFile(worldsDir, levelName, kind);
|
|
246
|
+
if (!fs.existsSync(file)) return { entries: [] };
|
|
247
|
+
try {
|
|
248
|
+
const arr = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
249
|
+
if (!Array.isArray(arr)) return { entries: [], parseFailedFile: file };
|
|
250
|
+
const out = [];
|
|
251
|
+
for (const e of arr) {
|
|
252
|
+
if (!e || typeof e !== "object") continue;
|
|
253
|
+
const packId = e.pack_id;
|
|
254
|
+
const ver = e.version;
|
|
255
|
+
if (typeof packId !== "string" || !packId) continue;
|
|
256
|
+
const version = Array.isArray(ver) && ver.length >= 3 ? [Number(ver[0]), Number(ver[1]), Number(ver[2])] : [1, 0, 0];
|
|
257
|
+
out.push({ pack_id: packId, version });
|
|
258
|
+
}
|
|
259
|
+
return { entries: out };
|
|
260
|
+
} catch {
|
|
261
|
+
return { entries: [], parseFailedFile: file };
|
|
262
|
+
}
|
|
217
263
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
format_version: 2,
|
|
221
|
-
header: {
|
|
222
|
-
name: header.name,
|
|
223
|
-
uuid: header.uuid,
|
|
224
|
-
version: header.version,
|
|
225
|
-
description: header.description ? `${header.description} (resource pack)` : "SFMC resource pack",
|
|
226
|
-
min_engine_version: [1, 21, 0],
|
|
227
|
-
},
|
|
228
|
-
modules: [
|
|
229
|
-
{
|
|
230
|
-
type: "resources",
|
|
231
|
-
uuid: crypto.randomUUID(),
|
|
232
|
-
version: header.version,
|
|
233
|
-
},
|
|
234
|
-
],
|
|
235
|
-
};
|
|
236
|
-
const file = path.join(outDir, "manifest.json");
|
|
237
|
-
await fs.promises.mkdir(outDir, { recursive: true });
|
|
238
|
-
await fs.promises.writeFile(file, JSON.stringify(manifest, null, 2) + "\n", "utf8");
|
|
264
|
+
function readWorldPackList(worldsDir, levelName, kind) {
|
|
265
|
+
return readWorldPackListResult(worldsDir, levelName, kind).entries;
|
|
239
266
|
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
export { copyFileAsync, copyDirAsync };
|
|
243
|
-
/* ── Discovery ─────────────────────────────────────────────────────────── */
|
|
244
|
-
/**
|
|
245
|
-
* Walk `<modulesDir>/<id>/resource_pack/` for every installed module and
|
|
246
|
-
* return a map { id: absoluteDir }. Modules without a resource_pack folder
|
|
247
|
-
* are silently skipped. Used by `assemble-rp` and the sfmc CLI to know which
|
|
248
|
-
* modules to merge into the resource pack output.
|
|
249
|
-
*/
|
|
250
|
-
export function scanModuleResourcePacks(modulesDir) {
|
|
251
|
-
const out = {};
|
|
252
|
-
if (!fs.existsSync(modulesDir))
|
|
253
|
-
return out;
|
|
254
|
-
for (const entry of fs.readdirSync(modulesDir, { withFileTypes: true })) {
|
|
255
|
-
if (!entry.isDirectory())
|
|
256
|
-
continue;
|
|
257
|
-
const rpDir = path.join(modulesDir, entry.name, "resource_pack");
|
|
258
|
-
if (fs.existsSync(rpDir)) {
|
|
259
|
-
out[entry.name] = rpDir;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
return out;
|
|
267
|
+
function worldPackListHas(worldsDir, levelName, kind, packUuid) {
|
|
268
|
+
return readWorldPackList(worldsDir, levelName, kind).some((e) => e.pack_id === packUuid);
|
|
263
269
|
}
|
|
264
|
-
|
|
270
|
+
export {
|
|
271
|
+
SFMC_PERMISSIONS,
|
|
272
|
+
assembleBehaviorPack,
|
|
273
|
+
assembleResourcePack,
|
|
274
|
+
bdsWorldLevelDir,
|
|
275
|
+
bdsWorldsDir,
|
|
276
|
+
configPermissionPath,
|
|
277
|
+
copyDirAsync,
|
|
278
|
+
copyFileAsync,
|
|
279
|
+
deployToBDS,
|
|
280
|
+
disablePackInWorld,
|
|
281
|
+
enablePackInWorld,
|
|
282
|
+
ensureConfigPermission,
|
|
283
|
+
hasConfigPermission,
|
|
284
|
+
loadModuleResourcePackMap,
|
|
285
|
+
randomUuid,
|
|
286
|
+
readLevelName,
|
|
287
|
+
readLevelNameSync,
|
|
288
|
+
readPackManifestHeader,
|
|
289
|
+
readWorldPackList,
|
|
290
|
+
readWorldPackListResult,
|
|
291
|
+
scanModuleResourcePacks,
|
|
292
|
+
serverPropertiesPath,
|
|
293
|
+
worldPackListFile,
|
|
294
|
+
worldPackListHas,
|
|
295
|
+
writeBehaviorPackManifest,
|
|
296
|
+
writePermissionsJson,
|
|
297
|
+
writeResourcePackManifest
|
|
298
|
+
};
|
|
299
|
+
//# sourceMappingURL=pack-manager.js.map
|
package/dist/pack-manager.js.map
CHANGED
|
@@ -1 +1,7 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/pack-manager.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * pack-manager.ts \u2014 Bedrock \u884C\u4E3A\u5305/\u8D44\u6E90\u5305 \u88C5\u914D + \u90E8\u7F72\u5230 BDS \u6839\u3002\n *\n * \u7EAF\u51FD\u6570\u5E93,\u4E24\u6761\u6D88\u8D39\u8DEF\u5F84:\n *\n * - \u540C\u8FDB\u7A0B(\u63A8\u8350): sfmc/pack-lifecycle \u7ECF `@sfmc-bds/bds-tools/pack-manager-lib`\n * \u76F4\u8FDE\u672C\u6A21\u5757\uFF08DIP\uFF09\uFF1Bworld-packs \u7B49\u540C\u7406\u3002\n * - CLI: `cli-pack-manager.js` \u4ECD\u66B4\u9732\u76F8\u540C\u52A8\u8BCD\uFF0C\u4F9B\u5916\u90E8\u811A\u672C/\u624B\u5DE5\u8C03\u8BD5\uFF1B\n * CLI \u53EA\u662F\u672C\u5E93\u7684\u8584\u9002\u914D\uFF0C\u4E0D\u518D\u662F sfmc \u4E3B\u8DEF\u5F84\u3002\n *\n * \u7EA6\u675F:\u672C\u6587\u4EF6\u4E0D\u5F15\u5165 esbuild / \u91CD\u578B npm-only \u5305\uFF0C\u4FDD\u6301\u53EF\u88AB Node \u5B50\u8FDB\u7A0B\u76F4\u63A5\u52A0\u8F7D\u3002\n *\n * \u5DF2\u6709\u4F9D\u8D56 (bds-tools/package.json):\n * - @sfmc-bds/sdk/logs createTerminalProgress: \u8FDB\u5EA6\u6761\uFF08BDS \u66F4\u65B0\u7B49\uFF09\n * - node-html-parser: changelog \u6293\u53D6 (\u672C\u6587\u4EF6\u7528\u4E0D\u5230)\n * - jszip: zip \u89E3\u538B(\u6A21\u5757 zip / BDS server.zip)\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { copyDirAsync, copyFileAsync } from \"./fsx.js\";\n\n/* \u2500\u2500 \u7C7B\u578B \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\nexport interface AssembleBehaviorPackOpts {\n /** Where the bundled scripts/main.js already exists (esbuild output dir) */\n srcDir: string;\n /** Output behavior pack directory (created if missing) */\n outDir: string;\n /** BP \u76EE\u5F55\u540D \u2014 \u9ED8\u8BA4 'sfmc-modules' */\n projectName: string;\n /** manifest.json \u7684 header.version [major, minor, patch]; \u9ED8\u8BA4 [1, 0, 0] */\n version?: [number, number, number] | undefined;\n /** manifest.json \u7684 description */\n description?: string | undefined;\n /** pack_icon.png \u6E90\u6587\u4EF6 (optional, \u4E0D\u63D0\u4F9B\u5219\u8DF3\u8FC7) */\n iconSrc?: string | undefined;\n /** \u7A33\u5B9A header.uuid;\u7701\u7565\u5219\u968F\u673A\u751F\u6210(\u9996\u6B21\u88C5\u914D) */\n uuid?: string | undefined;\n /** \u7A33\u5B9A script module uuid;\u7701\u7565\u5219\u968F\u673A */\n moduleUuid?: string | undefined;\n}\n\nexport interface AssembleResourcePackOpts {\n /** Modules whose resource_pack/** should be merged. Map<moduleId, resourcePackDir>. */\n moduleResourceDirs: Record<string, string>;\n /** Output resource pack directory (created if missing) */\n outDir: string;\n /** RP \u76EE\u5F55\u540D */\n projectName: string;\n /** manifest.json \u7684 header.version [major, minor, patch]; \u9ED8\u8BA4 [1, 0, 0] */\n version?: [number, number, number] | undefined;\n /** manifest.json \u7684 description */\n description?: string | undefined;\n /** \u7A33\u5B9A header.uuid;\u7701\u7565\u5219\u968F\u673A\u751F\u6210(\u9996\u6B21\u88C5\u914D) */\n uuid?: string | undefined;\n /** \u7A33\u5B9A resources module uuid;\u7701\u7565\u5219\u968F\u673A */\n moduleUuid?: string | undefined;\n}\n\nexport interface AssembleResult {\n uuid: string;\n version: [number, number, number];\n}\n\nexport interface DeployOpts {\n bdsRoot: string;\n levelName: string;\n /** \u5DF2\u7EC4\u88C5\u597D\u7684 BP \u6E90\u76EE\u5F55 */\n behaviorPackSrc: string;\n /** \u5DF2\u7EC4\u88C5\u597D\u7684 RP \u6E90\u76EE\u5F55 (\u53EF\u7701\u7565,\u53EA\u7528 BP \u4E5F\u5408\u6CD5) */\n resourcePackSrc?: string;\n /** BP \u76EE\u6807\u76EE\u5F55\u540D (worlds/<level>/behavior_packs/<bpName>) */\n bpName: string;\n /** RP \u76EE\u6807\u76EE\u5F55\u540D (worlds/<level>/resource_packs/<rpName>);\u7701\u7565\u65F6\u590D\u7528 bpName + '-rp' */\n rpName?: string;\n /**\n * \u65E0 resourcePackSrc \u65F6\u662F\u5426\u5220\u9664\u4E16\u754C\u5185\u5DF2\u6709 RP \u76EE\u5F55\u3002\n * \u7528\u4E8E\u6A21\u5757\u4E0D\u518D\u63D0\u4F9B RP \u65F6\u6E05\u7406\u805A\u5408\u5305\u6B8B\u7559(\u9ED8\u8BA4 false,\u907F\u514D\u8BEF\u5220\u672A\u58F0\u660E\u7684 RP)\u3002\n */\n clearResourcePack?: boolean;\n}\n\nexport interface DeployResult {\n bpDir: string;\n rpDir: string | null;\n}\n\nexport interface EnablePackOpts {\n worldsDir: string;\n levelName: string;\n kind: \"behavior\" | \"resource\";\n packUuid: string;\n version: [number, number, number];\n}\n\n/* \u2500\u2500 \u8DEF\u5F84\u5E38\u91CF \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/** SFMC \u5408\u6210 BP \u7684\u56FA\u5B9A @minecraft/* permissions,\u6240\u6709\u7528\u5230\u7684\u547D\u540D\u7A7A\u95F4\u90FD\u6253\u5F00\u3002 */\nexport const SFMC_PERMISSIONS = [\n \"@minecraft/server\",\n \"@minecraft/server-ui\",\n \"@minecraft/server-admin\",\n \"@minecraft/server-gametest\",\n \"@minecraft/server-net\",\n \"@minecraft/server-editor\",\n \"@minecraft/diagnostics\",\n] as const;\n\n/** `<bdsRoot>/server.properties` \u2014 level-name / telemetry \u7B49\u5171\u7528\uFF08DRY\uFF09 */\nexport function serverPropertiesPath(bdsRoot: string): string {\n return path.join(bdsRoot, \"server.properties\");\n}\n\n/** `<bdsRoot>/worlds` \u2014 enable-list / \u90E8\u7F72\u8C03\u7528\u65B9\u52FF\u518D\u786C\u62FC\uFF08Demeter\uFF09 */\nexport function bdsWorldsDir(bdsRoot: string): string {\n return path.join(bdsRoot, \"worlds\");\n}\n\n/** `<bdsRoot>/worlds/<level>` */\nexport function bdsWorldLevelDir(bdsRoot: string, levelName: string): string {\n return path.join(bdsWorldsDir(bdsRoot), levelName);\n}\n\n/** \u4E16\u754C enable-list JSON \u7EDD\u5BF9\u8DEF\u5F84\uFF08\u5355\u4E00\u6743\u5A01\uFF0C\u4F9B\u8BFB\u5199\u4E24\u4FA7\uFF09 */\nexport function worldPackListFile(\n worldsDir: string,\n levelName: string,\n kind: \"behavior\" | \"resource\"\n): string {\n const name = kind === \"behavior\" ? \"world_behavior_packs.json\" : \"world_resource_packs.json\";\n return path.join(worldsDir, levelName, name);\n}\n\n/** `<bdsRoot>/config/<bpUuid>/permission.json` \u2014 Script API \u6743\u9650\u6587\u4EF6\u6743\u5A01\u8DEF\u5F84 */\nexport function configPermissionPath(bdsRoot: string, bpUuid: string): string {\n return path.join(bdsRoot, \"config\", bpUuid, \"permission.json\");\n}\n\n/** \u662F\u5426\u5DF2\u6709 Script API permission.json\uFF08\u53EA\u8BFB\uFF0C\u4F9B preflight/status\uFF09 */\nexport function hasConfigPermission(bdsRoot: string, bpUuid: string): boolean {\n return fs.existsSync(configPermissionPath(bdsRoot, bpUuid));\n}\n\n/** \u968F\u673A\u751F\u6210 BP/RP manifest.json header.uuid (RFC 4122 v4) */\nexport function randomUuid(): string {\n /* crypto.randomUUID \u662F Node 19+ \u5185\u7F6E,\u8FD9\u91CC\u76F4\u63A5\u7528 */\n return crypto.randomUUID();\n}\n\n/* \u2500\u2500 \u9AA8\u67B6\u51FD\u6570 (Commit 5 \u5B9E\u73B0) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/**\n * Assemble a Bedrock behavior pack directory at `outDir` from a prebuilt\n * `srcDir` (which must already contain `scripts/main.js` plus whatever else\n * was bundled by esbuild) and write a fresh `manifest.json` + `permissions.json`.\n *\n * The caller is responsible for running esbuild first; pack-manager does not\n * bundle scripts. That decoupling keeps pack assembly independent of the bundler.\n */\nexport async function assembleBehaviorPack(opts: AssembleBehaviorPackOpts): Promise<AssembleResult> {\n const version = opts.version ?? [1, 0, 0];\n const bpUuid = opts.uuid ?? randomUuid();\n await fs.promises.rm(opts.outDir, { recursive: true, force: true });\n await fs.promises.mkdir(opts.outDir, { recursive: true });\n if (fs.existsSync(opts.srcDir)) {\n await copyDirAsync(opts.srcDir, opts.outDir);\n } else {\n await fs.promises.mkdir(path.join(opts.outDir, \"scripts\"), { recursive: true });\n await fs.promises.writeFile(path.join(opts.outDir, \"scripts\", \"main.js\"), \"/* no scripts */\\n\", \"utf8\");\n }\n await writeBehaviorPackManifest(opts.outDir, {\n name: opts.projectName,\n uuid: bpUuid,\n version,\n description: opts.description,\n moduleUuid: opts.moduleUuid,\n });\n if (opts.iconSrc && fs.existsSync(opts.iconSrc)) {\n await copyFileAsync(opts.iconSrc, path.join(opts.outDir, \"pack_icon.png\"));\n }\n await writePermissionsJson(opts.outDir);\n return { uuid: bpUuid, version };\n}\n\n/**\n * Merge every enabled module's `resource_pack/**` tree into one RP directory\n * at `outDir`, with a single fresh `manifest.json`. Per-module subfolders are\n * preserved so resource pack authors can disambiguate (e.g. `peace/textures/...`).\n */\nexport async function assembleResourcePack(opts: AssembleResourcePackOpts): Promise<AssembleResult> {\n const version = opts.version ?? [1, 0, 0];\n const rpUuid = opts.uuid ?? randomUuid();\n await fs.promises.rm(opts.outDir, { recursive: true, force: true });\n await fs.promises.mkdir(opts.outDir, { recursive: true });\n for (const [moduleId, rpDir] of Object.entries(opts.moduleResourceDirs)) {\n if (!fs.existsSync(rpDir)) continue;\n const dst = path.join(opts.outDir, moduleId);\n await fs.promises.mkdir(dst, { recursive: true });\n await copyDirAsync(rpDir, dst);\n }\n await writeResourcePackManifest(opts.outDir, {\n name: opts.projectName,\n uuid: rpUuid,\n version,\n description: opts.description,\n moduleUuid: opts.moduleUuid,\n });\n return { uuid: rpUuid, version };\n}\n\n/**\n * Read the `level-name=` value from `<bdsRoot>/server.properties`.\n * Falls back to \"Bedrock level\" (BDS default) when the file is missing or\n * the key is absent.\n */\nfunction parseLevelNameFromProperties(text: string): string {\n for (const line of text.split(/\\r?\\n/)) {\n const m = /^\\s*level-name\\s*=\\s*(.+?)\\s*$/.exec(line);\n if (m && m[1]) return m[1];\n }\n return \"Bedrock level\";\n}\n\n/** \u540C\u6B65\u8BFB level-name\uFF08\u4F9B sfmc resolveBdsContext \u7B49\u540C\u8FDB\u7A0B\u8C03\u7528\u65B9\uFF0CDRY\uFF09\u3002 */\nexport function readLevelNameSync(bdsRoot: string): string {\n const file = serverPropertiesPath(bdsRoot);\n if (!fs.existsSync(file)) return \"Bedrock level\";\n return parseLevelNameFromProperties(fs.readFileSync(file, \"utf8\"));\n}\n\n/** \u4E0E sync \u540C\u5951\u7EA6\uFF1BCLI / async \u8C03\u7528\u65B9\u8D70\u6B64\u5165\u53E3\uFF08LSP\uFF09 */\nexport async function readLevelName(bdsRoot: string): Promise<string> {\n return readLevelNameSync(bdsRoot);\n}\n\n/**\n * Copy BP/RP source dirs into the world's behavior_packs/ + resource_packs/\n * folders, and write a fresh `permissions.json` into the BP target.\n *\n * Does NOT edit world_behavior_packs.json \u2014 that's a separate step the caller\n * must invoke after restart, because BDS only reads that file at startup.\n */\nexport async function deployToBDS(opts: DeployOpts): Promise<DeployResult> {\n /* levelDir = worlds/<level>\uFF1B\u4E0E EnablePackOpts.worldsDir(=worlds/) \u8BED\u4E49\u4E0D\u540C \u2014 \u52FF\u6DF7\u7528\uFF08LSP\uFF09 */\n const levelDir = bdsWorldLevelDir(opts.bdsRoot, opts.levelName);\n const bpDst = path.join(levelDir, \"behavior_packs\", opts.bpName);\n const rpDst = path.join(levelDir, \"resource_packs\", opts.rpName ?? `${opts.bpName}-rp`);\n await fs.promises.mkdir(levelDir, { recursive: true });\n await fs.promises.rm(bpDst, { recursive: true, force: true });\n await copyDirAsync(opts.behaviorPackSrc, bpDst);\n await writePermissionsJson(bpDst);\n let rpDir: string | null = null;\n if (opts.resourcePackSrc && fs.existsSync(opts.resourcePackSrc)) {\n await fs.promises.rm(rpDst, { recursive: true, force: true });\n await copyDirAsync(opts.resourcePackSrc, rpDst);\n rpDir = rpDst;\n } else if (opts.clearResourcePack) {\n /* \u8C03\u7528\u65B9\u663E\u5F0F\u58F0\u660E\u4E0D\u518D\u90E8\u7F72 RP \u2014 \u6E05\u6389\u805A\u5408 RP \u76EE\u5F55\u6B8B\u7559 */\n await fs.promises.rm(rpDst, { recursive: true, force: true });\n }\n return { bpDir: bpDst, rpDir };\n}\n\n/**\n * \u786E\u4FDD BDS Script API \u4FA7 `<bdsRoot>/config/<bpUuid>/permission.json` \u5B58\u5728\u3002\n * \u5DF2\u5B58\u5728\u5219\u8DF3\u8FC7(\u4E0D\u8986\u76D6\u7528\u6237\u624B\u5DE5\u6539\u52A8)\u3002\n * @returns true = \u65B0\u5199\u5165; false = \u5DF2\u5B58\u5728\u8DF3\u8FC7\n */\nexport async function ensureConfigPermission(bdsRoot: string, bpUuid: string): Promise<boolean> {\n const file = configPermissionPath(bdsRoot, bpUuid);\n if (fs.existsSync(file)) return false;\n const dir = path.dirname(file);\n await fs.promises.mkdir(dir, { recursive: true });\n const payload = { allowed_modules: [...SFMC_PERMISSIONS] };\n const tmp = path.join(dir, `.permission.${process.pid}.tmp`);\n await fs.promises.writeFile(tmp, JSON.stringify(payload, null, 2) + \"\\n\", \"utf8\");\n await fs.promises.rename(tmp, file);\n return true;\n}\n\n/** \u4ECE\u5DF2\u88C5\u914D BP/RP \u76EE\u5F55\u8BFB\u53D6 header.uuid + version;\u5931\u8D25\u8FD4\u56DE null\u3002 */\nexport function readPackManifestHeader(\n packDir: string\n): { uuid: string; version: [number, number, number]; moduleUuid?: string } | null {\n const file = path.join(packDir, \"manifest.json\");\n if (!fs.existsSync(file)) return null;\n try {\n const raw = JSON.parse(fs.readFileSync(file, \"utf8\")) as {\n header?: { uuid?: string; version?: number[] };\n modules?: Array<{ uuid?: string }>;\n };\n const uuid = raw.header?.uuid;\n const ver = raw.header?.version;\n if (typeof uuid !== \"string\" || !Array.isArray(ver) || ver.length < 3) return null;\n const version: [number, number, number] = [Number(ver[0]), Number(ver[1]), Number(ver[2])];\n const moduleUuid = raw.modules?.[0]?.uuid;\n return { uuid, version, ...(typeof moduleUuid === \"string\" ? { moduleUuid } : {}) };\n } catch {\n return null;\n }\n}\n\n/**\n * Write the seven `@minecraft/*` allowed_modules into a behavior pack's\n * `permissions.json`. Idempotent: rewrites any pre-existing file.\n */\nexport async function writePermissionsJson(bpDir: string): Promise<void> {\n const payload = { allowed_modules: [...SFMC_PERMISSIONS] };\n await fs.promises.mkdir(bpDir, { recursive: true });\n const tmp = path.join(bpDir, `.permissions.${process.pid}.tmp`);\n await fs.promises.writeFile(tmp, JSON.stringify(payload, null, 2) + \"\\n\", \"utf8\");\n await fs.promises.rename(tmp, path.join(bpDir, \"permissions.json\"));\n}\n\n/**\n * Add `{ pack_id, version }` to `worlds/<level>/world_behavior_packs.json`\n * (or `world_resource_packs.json`). If the pack_id already exists, replace its\n * version. File missing \u2192 initialize as `[]`.\n */\nexport async function enablePackInWorld(opts: EnablePackOpts): Promise<void> {\n await editWorldPackList(opts, \"enable\");\n}\n\n/** Remove a pack_id from the world's enable-list JSON. */\nexport async function disablePackInWorld(opts: EnablePackOpts): Promise<void> {\n await editWorldPackList(opts, \"disable\");\n}\n\ninterface WorldPackEntry {\n pack_id: string;\n version: [number, number, number];\n}\n\nasync function editWorldPackList(\n opts: EnablePackOpts,\n mode: \"enable\" | \"disable\"\n): Promise<void> {\n const file = worldPackListFile(opts.worldsDir, opts.levelName, opts.kind);\n /* \u4E0E readWorldPackList \u540C\u6E90\u89E3\u6790,\u518D\u5199\u56DE(DRY);\u5F02\u6B65\u5199\u8DEF\u5F84\u4FDD\u7559\u539F\u8BED\u4E49 */\n let entries: WorldPackEntry[] = readWorldPackList(opts.worldsDir, opts.levelName, opts.kind);\n const idx = entries.findIndex((e) => e.pack_id === opts.packUuid);\n if (mode === \"enable\") {\n const next: WorldPackEntry = { pack_id: opts.packUuid, version: opts.version };\n if (idx >= 0) entries[idx] = next;\n else entries.push(next);\n } else {\n if (idx >= 0) entries.splice(idx, 1);\n }\n await fs.promises.mkdir(path.dirname(file), { recursive: true });\n const tmp = `${file}.${process.pid}.tmp`;\n await fs.promises.writeFile(tmp, JSON.stringify(entries, null, 2) + \"\\n\", \"utf8\");\n await fs.promises.rename(tmp, file);\n}\n\n/* \u2500\u2500 \u4F4E\u5C42 helpers (Commit 5 \u5B9E\u73B0) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\nexport async function writeBehaviorPackManifest(\n outDir: string,\n header: {\n name: string;\n uuid: string;\n version: [number, number, number];\n description?: string | undefined;\n moduleUuid?: string | undefined;\n }\n): Promise<void> {\n const manifest = {\n format_version: 2,\n header: {\n name: header.name,\n uuid: header.uuid,\n version: header.version,\n description: header.description ? `${header.description} (behavior pack)` : \"SFMC behavior pack\",\n min_engine_version: [1, 21, 0],\n },\n modules: [\n {\n type: \"script\",\n language: \"javascript\",\n entry: \"scripts/main.js\",\n uuid: header.moduleUuid ?? crypto.randomUUID(),\n version: header.version,\n },\n ],\n dependencies: [\n { module_name: \"@minecraft/server\", version: \"1.18.0\" },\n ],\n };\n const file = path.join(outDir, \"manifest.json\");\n await fs.promises.mkdir(outDir, { recursive: true });\n await fs.promises.writeFile(file, JSON.stringify(manifest, null, 2) + \"\\n\", \"utf8\");\n}\n\nexport async function writeResourcePackManifest(\n outDir: string,\n header: {\n name: string;\n uuid: string;\n version: [number, number, number];\n description?: string | undefined;\n moduleUuid?: string | undefined;\n }\n): Promise<void> {\n const manifest = {\n format_version: 2,\n header: {\n name: header.name,\n uuid: header.uuid,\n version: header.version,\n description: header.description ? `${header.description} (resource pack)` : \"SFMC resource pack\",\n min_engine_version: [1, 21, 0],\n },\n modules: [\n {\n type: \"resources\",\n uuid: header.moduleUuid ?? crypto.randomUUID(),\n version: header.version,\n },\n ],\n };\n const file = path.join(outDir, \"manifest.json\");\n await fs.promises.mkdir(outDir, { recursive: true });\n await fs.promises.writeFile(file, JSON.stringify(manifest, null, 2) + \"\\n\", \"utf8\");\n}\n\n/* Re-export copyFileAsync so callers can copy icon without\n * pulling in the full fsx surface area. */\nexport { copyFileAsync, copyDirAsync };\n\n/* \u2500\u2500 Discovery \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n/**\n * Walk `<modulesDir>/<id>/resource_pack/` for every installed module and\n * return a map { id: absoluteDir }. Modules without a resource_pack folder\n * are silently skipped. Used by `assemble-rp` and the sfmc CLI to know which\n * modules to merge into the resource pack output.\n */\nexport function scanModuleResourcePacks(modulesDir: string): Record<string, string> {\n const out: Record<string, string> = {};\n if (!fs.existsSync(modulesDir)) return out;\n for (const entry of fs.readdirSync(modulesDir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n const rpDir = path.join(modulesDir, entry.name, \"resource_pack\");\n if (fs.existsSync(rpDir)) {\n out[entry.name] = rpDir;\n }\n }\n return out;\n}\n\n/**\n * \u4ECE JSON \u6587\u4EF6\u52A0\u8F7D\u663E\u5F0F moduleId \u2192 resource_pack \u76EE\u5F55\u6620\u5C04\u3002\n * \u4F9B assemble-rp --modules-json \u4F7F\u7528,\u907F\u514D\u8C03\u7528\u65B9\u518D\u505A\u4E34\u65F6\u76EE\u5F55\u955C\u50CF(OCP/DRY)\u3002\n */\nexport function loadModuleResourcePackMap(jsonPath: string): Record<string, string> {\n const raw = JSON.parse(fs.readFileSync(jsonPath, \"utf8\")) as unknown;\n if (!raw || typeof raw !== \"object\" || Array.isArray(raw)) {\n throw new Error(`modules-json must be an object: ${jsonPath}`);\n }\n const out: Record<string, string> = {};\n for (const [id, dir] of Object.entries(raw as Record<string, unknown>)) {\n if (typeof id !== \"string\" || !id || typeof dir !== \"string\" || !dir) continue;\n const abs = path.resolve(dir);\n if (!fs.existsSync(abs)) {\n throw new Error(`modules-json entry missing: ${id} \u2192 ${abs}`);\n }\n out[id] = abs;\n }\n return out;\n}\n\n/**\n * \u8BFB\u53D6\u4E16\u754C enable-list(\u5355\u4E00\u6743\u5A01,\u4F9B has-pack / list-packs / \u8C03\u7528\u65B9\u590D\u7528 \u2014 DRY)\u3002\n * \u6587\u4EF6\u7F3A\u5931 \u2192 entries=[]\uFF1BJSON \u635F\u574F \u2192 entries=[] \u4E14 parseFailedFile \u6709\u503C\uFF08\u4F9B doctor \u533A\u5206\uFF09\u3002\n */\nexport type WorldPackListReadResult = {\n entries: Array<{ pack_id: string; version: [number, number, number] }>;\n /** \u6587\u4EF6\u5B58\u5728\u4F46\u89E3\u6790\u5931\u8D25\u65F6\u4E3A\u8BE5 JSON \u7EDD\u5BF9\u8DEF\u5F84 */\n parseFailedFile?: string;\n};\n\nexport function readWorldPackListResult(\n worldsDir: string,\n levelName: string,\n kind: \"behavior\" | \"resource\"\n): WorldPackListReadResult {\n const file = worldPackListFile(worldsDir, levelName, kind);\n if (!fs.existsSync(file)) return { entries: [] };\n try {\n const arr = JSON.parse(fs.readFileSync(file, \"utf8\")) as unknown;\n if (!Array.isArray(arr)) return { entries: [], parseFailedFile: file };\n const out: Array<{ pack_id: string; version: [number, number, number] }> = [];\n for (const e of arr) {\n if (!e || typeof e !== \"object\") continue;\n const packId = (e as { pack_id?: unknown }).pack_id;\n const ver = (e as { version?: unknown }).version;\n if (typeof packId !== \"string\" || !packId) continue;\n const version: [number, number, number] =\n Array.isArray(ver) && ver.length >= 3\n ? [Number(ver[0]), Number(ver[1]), Number(ver[2])]\n : [1, 0, 0];\n out.push({ pack_id: packId, version });\n }\n return { entries: out };\n } catch {\n return { entries: [], parseFailedFile: file };\n }\n}\n\n/** \u517C\u5BB9\u8BFB\u4FA7\uFF1A\u53EA\u8981 entries\uFF08\u635F\u574F\u65F6\u4E0E\u7F3A\u5931\u540C\u4E3A []\uFF09\u3002\u8BE6\u7EC6\u7ED3\u679C\u89C1 readWorldPackListResult\u3002 */\nexport function readWorldPackList(\n worldsDir: string,\n levelName: string,\n kind: \"behavior\" | \"resource\"\n): Array<{ pack_id: string; version: [number, number, number] }> {\n return readWorldPackListResult(worldsDir, levelName, kind).entries;\n}\n\n/** \u4E16\u754C enable-list \u662F\u5426\u5DF2\u542B\u6307\u5B9A pack_id(\u53EA\u8BFB,\u4F9B preflight \u590D\u7528)\u3002 */\nexport function worldPackListHas(\n worldsDir: string,\n levelName: string,\n kind: \"behavior\" | \"resource\",\n packUuid: string\n): boolean {\n return readWorldPackList(worldsDir, levelName, kind).some((e) => e.pack_id === packUuid);\n}"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|