@sfmc-bds/bds-tools 0.2.0-beta.9 → 0.2.1
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/LICENSE +663 -0
- package/README.md +1 -1
- package/dist/bds-manager.d.ts +16 -6
- package/dist/bds-manager.d.ts.map +1 -1
- package/dist/bds-manager.js +22 -4
- package/dist/bds-manager.js.map +2 -2
- package/dist/changelog.d.ts +11 -7
- package/dist/changelog.d.ts.map +1 -1
- package/dist/changelog.js +60 -34
- package/dist/changelog.js.map +2 -2
- package/dist/check-update.d.ts.map +1 -1
- package/dist/check-update.js +56 -18
- package/dist/check-update.js.map +2 -2
- package/dist/cli-pack-manager.js +11 -1
- package/dist/cli-pack-manager.js.map +2 -2
- package/dist/dependency-negotiator.d.ts +73 -0
- package/dist/dependency-negotiator.d.ts.map +1 -0
- package/dist/dependency-negotiator.js +151 -0
- package/dist/dependency-negotiator.js.map +7 -0
- package/dist/fsx.d.ts +15 -7
- package/dist/fsx.d.ts.map +1 -1
- package/dist/fsx.js +67 -8
- package/dist/fsx.js.map +2 -2
- package/dist/http.d.ts +49 -11
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js.map +2 -2
- package/dist/level-dat.d.ts +105 -0
- package/dist/level-dat.d.ts.map +1 -0
- package/dist/level-dat.js +490 -0
- package/dist/level-dat.js.map +7 -0
- package/dist/pack-manager.d.ts +41 -34
- package/dist/pack-manager.d.ts.map +1 -1
- package/dist/pack-manager.js +73 -24
- package/dist/pack-manager.js.map +2 -2
- package/dist/qq-events-notify.d.ts +1 -1
- package/dist/qq-events-notify.d.ts.map +1 -1
- package/dist/qq-events-notify.js.map +1 -1
- package/dist/qqutil.d.ts +10 -6
- package/dist/qqutil.d.ts.map +1 -1
- package/dist/qqutil.js +14 -12
- package/dist/qqutil.js.map +2 -2
- package/dist/rollback.d.ts.map +1 -1
- package/dist/rollback.js +2 -2
- package/dist/rollback.js.map +2 -2
- package/dist/server-properties-i18n.d.ts +17 -0
- package/dist/server-properties-i18n.d.ts.map +1 -0
- package/dist/server-properties-i18n.js +201 -0
- package/dist/server-properties-i18n.js.map +7 -0
- package/dist/server-properties.d.ts +25 -0
- package/dist/server-properties.d.ts.map +1 -1
- package/dist/server-properties.js +141 -1
- package/dist/server-properties.js.map +2 -2
- package/dist/types.d.ts +1 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/upstream.d.ts +14 -6
- package/dist/upstream.d.ts.map +1 -1
- package/dist/upstream.js.map +2 -2
- package/dist/world-packs.d.ts +106 -3
- package/dist/world-packs.d.ts.map +1 -1
- package/dist/world-packs.js +245 -10
- package/dist/world-packs.js.map +3 -3
- package/package.json +19 -14
- package/dist/qq-events-notify.test.d.ts +0 -5
- package/dist/qq-events-notify.test.d.ts.map +0 -1
- package/dist/qq-events-notify.test.js +0 -41
- package/dist/qq-events-notify.test.js.map +0 -7
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
const TAG_END = 0;
|
|
3
|
+
const TAG_BYTE = 1;
|
|
4
|
+
const TAG_SHORT = 2;
|
|
5
|
+
const TAG_INT = 3;
|
|
6
|
+
const TAG_LONG = 4;
|
|
7
|
+
const TAG_FLOAT = 5;
|
|
8
|
+
const TAG_DOUBLE = 6;
|
|
9
|
+
const TAG_BYTE_ARRAY = 7;
|
|
10
|
+
const TAG_STRING = 8;
|
|
11
|
+
const TAG_LIST = 9;
|
|
12
|
+
const TAG_COMPOUND = 10;
|
|
13
|
+
const TAG_INT_ARRAY = 11;
|
|
14
|
+
const TAG_LONG_ARRAY = 12;
|
|
15
|
+
const KNOWN_EXPERIMENTS = [
|
|
16
|
+
{
|
|
17
|
+
id: "gametest",
|
|
18
|
+
nbtKey: "gametest",
|
|
19
|
+
nameZh: "\u6D4B\u8BD5\u7248 API",
|
|
20
|
+
nameEn: "Beta APIs (gametest)",
|
|
21
|
+
aliases: ["beta", "beta_apis", "betapis", "gametest"]
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
id: "upcoming_creator_features",
|
|
25
|
+
nbtKey: "upcoming_creator_features",
|
|
26
|
+
nameZh: "\u5373\u5C06\u63A8\u51FA\u7684\u521B\u4F5C\u8005\u529F\u80FD",
|
|
27
|
+
nameEn: "Upcoming Creator Features",
|
|
28
|
+
aliases: ["upcoming", "creator_features", "upcoming_features"]
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
id: "experimental_creator_cameras",
|
|
32
|
+
nbtKey: "experimental_creator_cameras",
|
|
33
|
+
nameZh: "\u521B\u5EFA\u8005\u7167\u76F8\u673A\u7684\u5B9E\u9A8C\u6027\u529F\u80FD",
|
|
34
|
+
nameEn: "Experimental Creator Cameras",
|
|
35
|
+
aliases: ["camera", "cameras", "creator_cameras", "creator_camera"]
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: "voxel_shapes",
|
|
39
|
+
nbtKey: "voxel_shapes",
|
|
40
|
+
nameZh: "\u5B9E\u9A8C\u6027Voxel\u5F62\u72B6\u7279\u5F81",
|
|
41
|
+
nameEn: "Experimental Voxel Shapes",
|
|
42
|
+
aliases: ["voxel", "voxel_shape", "experimental_voxel_shapes", "voxelshapes"]
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
id: "villager_trades_rebalance",
|
|
46
|
+
nbtKey: "villager_trades_rebalance",
|
|
47
|
+
nameZh: "\u6751\u6C11\u8D38\u6613\u518D\u5E73\u8861",
|
|
48
|
+
nameEn: "Villager Trade Rebalance",
|
|
49
|
+
aliases: ["villager", "trades", "villager_trades", "trade_rebalance"]
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: "drop_3_2026",
|
|
53
|
+
nbtKey: "drop_3_2026",
|
|
54
|
+
nameZh: "2026\u5E74\u7B2C3\u6B21\u66F4\u65B0",
|
|
55
|
+
nameEn: "Drop 3 of 2026",
|
|
56
|
+
aliases: [
|
|
57
|
+
"drop3",
|
|
58
|
+
"drop_3",
|
|
59
|
+
"drop_3_2026",
|
|
60
|
+
"wilderness",
|
|
61
|
+
"wilderness_bound",
|
|
62
|
+
"update_2026_drop_3",
|
|
63
|
+
"update_26_3",
|
|
64
|
+
"update_drop_3"
|
|
65
|
+
],
|
|
66
|
+
extraExpTags: ["update_2026_drop_3"]
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
id: "education",
|
|
70
|
+
nbtKey: "educationFeaturesEnabled",
|
|
71
|
+
nameZh: "Minecraft Education \u529F\u80FD",
|
|
72
|
+
nameEn: "Minecraft Education Features",
|
|
73
|
+
isRootTag: true,
|
|
74
|
+
aliases: ["edu", "education", "education_edition", "educationfeatures"],
|
|
75
|
+
extraExpTags: ["education"]
|
|
76
|
+
}
|
|
77
|
+
];
|
|
78
|
+
function resolveExperimentDefinition(query) {
|
|
79
|
+
const q = query.trim().toLowerCase().replace(/[-_]/g, "");
|
|
80
|
+
for (const def of KNOWN_EXPERIMENTS) {
|
|
81
|
+
if (def.id.replace(/[-_]/g, "") === q) return def;
|
|
82
|
+
if (def.nbtKey.replace(/[-_]/g, "") === q) return def;
|
|
83
|
+
if (def.aliases) {
|
|
84
|
+
for (const a of def.aliases) {
|
|
85
|
+
if (a.replace(/[-_]/g, "") === q) return def;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
function skipNbtPayload(buf, offset, type) {
|
|
92
|
+
switch (type) {
|
|
93
|
+
case TAG_BYTE:
|
|
94
|
+
return offset + 1;
|
|
95
|
+
case TAG_SHORT:
|
|
96
|
+
return offset + 2;
|
|
97
|
+
case TAG_INT:
|
|
98
|
+
case TAG_FLOAT:
|
|
99
|
+
return offset + 4;
|
|
100
|
+
case TAG_LONG:
|
|
101
|
+
case TAG_DOUBLE:
|
|
102
|
+
return offset + 8;
|
|
103
|
+
case TAG_BYTE_ARRAY: {
|
|
104
|
+
if (offset + 4 > buf.length) throw new Error("Unexpected EOF reading TAG_Byte_Array length");
|
|
105
|
+
const len = buf.readInt32LE(offset);
|
|
106
|
+
return offset + 4 + Math.max(0, len);
|
|
107
|
+
}
|
|
108
|
+
case TAG_STRING: {
|
|
109
|
+
if (offset + 2 > buf.length) throw new Error("Unexpected EOF reading TAG_String length");
|
|
110
|
+
const len = buf.readUInt16LE(offset);
|
|
111
|
+
return offset + 2 + len;
|
|
112
|
+
}
|
|
113
|
+
case TAG_LIST: {
|
|
114
|
+
if (offset + 5 > buf.length) throw new Error("Unexpected EOF reading TAG_List header");
|
|
115
|
+
const elemType = buf.readUInt8(offset);
|
|
116
|
+
const count = buf.readInt32LE(offset + 1);
|
|
117
|
+
let cur = offset + 5;
|
|
118
|
+
for (let i = 0; i < count; i++) {
|
|
119
|
+
cur = skipNbtPayload(buf, cur, elemType);
|
|
120
|
+
}
|
|
121
|
+
return cur;
|
|
122
|
+
}
|
|
123
|
+
case TAG_COMPOUND: {
|
|
124
|
+
let cur = offset;
|
|
125
|
+
while (cur < buf.length) {
|
|
126
|
+
const t = buf.readUInt8(cur);
|
|
127
|
+
if (t === TAG_END) {
|
|
128
|
+
return cur + 1;
|
|
129
|
+
}
|
|
130
|
+
if (cur + 3 > buf.length) throw new Error("Unexpected EOF reading compound child header");
|
|
131
|
+
const nameLen = buf.readUInt16LE(cur + 1);
|
|
132
|
+
const childValOffset = cur + 3 + nameLen;
|
|
133
|
+
cur = skipNbtPayload(buf, childValOffset, t);
|
|
134
|
+
}
|
|
135
|
+
return cur;
|
|
136
|
+
}
|
|
137
|
+
case TAG_INT_ARRAY: {
|
|
138
|
+
if (offset + 4 > buf.length) throw new Error("Unexpected EOF reading TAG_Int_Array length");
|
|
139
|
+
const len = buf.readInt32LE(offset);
|
|
140
|
+
return offset + 4 + Math.max(0, len) * 4;
|
|
141
|
+
}
|
|
142
|
+
case TAG_LONG_ARRAY: {
|
|
143
|
+
if (offset + 4 > buf.length) throw new Error("Unexpected EOF reading TAG_Long_Array length");
|
|
144
|
+
const len = buf.readInt32LE(offset);
|
|
145
|
+
return offset + 4 + Math.max(0, len) * 8;
|
|
146
|
+
}
|
|
147
|
+
default:
|
|
148
|
+
throw new Error(`Unsupported or unknown NBT tag type: ${type} at offset ${offset}`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
function parseCompoundChildren(buf, compoundValueOffset) {
|
|
152
|
+
const children = /* @__PURE__ */ new Map();
|
|
153
|
+
let cur = compoundValueOffset;
|
|
154
|
+
while (cur < buf.length) {
|
|
155
|
+
const tagType = buf.readUInt8(cur);
|
|
156
|
+
if (tagType === TAG_END) {
|
|
157
|
+
return { children, compoundEndOffset: cur + 1 };
|
|
158
|
+
}
|
|
159
|
+
if (cur + 3 > buf.length) {
|
|
160
|
+
throw new Error(`Unexpected EOF reading named tag header at offset ${cur}`);
|
|
161
|
+
}
|
|
162
|
+
const nameLen = buf.readUInt16LE(cur + 1);
|
|
163
|
+
const nameOffset = cur + 3;
|
|
164
|
+
if (nameOffset + nameLen > buf.length) {
|
|
165
|
+
throw new Error(`Unexpected EOF reading tag name at offset ${cur}`);
|
|
166
|
+
}
|
|
167
|
+
const name = buf.toString("utf8", nameOffset, nameOffset + nameLen);
|
|
168
|
+
const valOffset = nameOffset + nameLen;
|
|
169
|
+
const endOffset = skipNbtPayload(buf, valOffset, tagType);
|
|
170
|
+
let val = void 0;
|
|
171
|
+
if (tagType === TAG_BYTE) {
|
|
172
|
+
val = buf.readInt8(valOffset);
|
|
173
|
+
} else if (tagType === TAG_INT) {
|
|
174
|
+
val = buf.readInt32LE(valOffset);
|
|
175
|
+
} else if (tagType === TAG_STRING) {
|
|
176
|
+
const sLen = buf.readUInt16LE(valOffset);
|
|
177
|
+
val = buf.toString("utf8", valOffset + 2, valOffset + 2 + sLen);
|
|
178
|
+
}
|
|
179
|
+
children.set(name, {
|
|
180
|
+
type: tagType,
|
|
181
|
+
name,
|
|
182
|
+
startOffset: cur,
|
|
183
|
+
nameOffset,
|
|
184
|
+
valueOffset: valOffset,
|
|
185
|
+
endOffset,
|
|
186
|
+
value: val
|
|
187
|
+
});
|
|
188
|
+
cur = endOffset;
|
|
189
|
+
}
|
|
190
|
+
return { children, compoundEndOffset: cur };
|
|
191
|
+
}
|
|
192
|
+
function parseBedrockLevelDat(buf) {
|
|
193
|
+
if (buf.length < 8) {
|
|
194
|
+
throw new Error("Invalid level.dat: buffer smaller than 8-byte header");
|
|
195
|
+
}
|
|
196
|
+
const version = buf.readUInt32LE(0);
|
|
197
|
+
const dataLength = buf.readUInt32LE(4);
|
|
198
|
+
if (buf.length < 9 || buf.readUInt8(8) !== TAG_COMPOUND) {
|
|
199
|
+
throw new Error("Invalid level.dat: root tag is not TAG_Compound");
|
|
200
|
+
}
|
|
201
|
+
const rootNameLen = buf.readUInt16LE(9);
|
|
202
|
+
const rootCompoundName = buf.toString("utf8", 11, 11 + rootNameLen);
|
|
203
|
+
const rootValueOffset = 11 + rootNameLen;
|
|
204
|
+
const { children: rootChildren, compoundEndOffset: rootEndOffset } = parseCompoundChildren(buf, rootValueOffset);
|
|
205
|
+
return {
|
|
206
|
+
version,
|
|
207
|
+
dataLength,
|
|
208
|
+
rootCompoundName,
|
|
209
|
+
rootChildren,
|
|
210
|
+
rootEndOffset
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
function readLevelDatExperiments(levelDatPath) {
|
|
214
|
+
if (!fs.existsSync(levelDatPath)) return null;
|
|
215
|
+
try {
|
|
216
|
+
const buf = fs.readFileSync(levelDatPath);
|
|
217
|
+
const parsed = parseBedrockLevelDat(buf);
|
|
218
|
+
let experimentsEverUsed = false;
|
|
219
|
+
const everUsedTag = parsed.rootChildren.get("experiments_ever_used");
|
|
220
|
+
if (everUsedTag && everUsedTag.type === TAG_BYTE && Number(everUsedTag.value) === 1) {
|
|
221
|
+
experimentsEverUsed = true;
|
|
222
|
+
}
|
|
223
|
+
let savedWithToggledExperiments = false;
|
|
224
|
+
const savedTag = parsed.rootChildren.get("saved_with_toggled_experiments");
|
|
225
|
+
if (savedTag && savedTag.type === TAG_BYTE && Number(savedTag.value) === 1) {
|
|
226
|
+
savedWithToggledExperiments = true;
|
|
227
|
+
}
|
|
228
|
+
const experiments = {};
|
|
229
|
+
let hasBetaApis = false;
|
|
230
|
+
const expCompoundTag = parsed.rootChildren.get("experiments");
|
|
231
|
+
if (expCompoundTag && expCompoundTag.type === TAG_COMPOUND) {
|
|
232
|
+
const expChildren = parseCompoundChildren(buf, expCompoundTag.valueOffset).children;
|
|
233
|
+
const innerEverUsed = expChildren.get("experiments_ever_used");
|
|
234
|
+
if (innerEverUsed && Number(innerEverUsed.value) === 1) {
|
|
235
|
+
experimentsEverUsed = true;
|
|
236
|
+
}
|
|
237
|
+
const innerSaved = expChildren.get("saved_with_toggled_experiments");
|
|
238
|
+
if (innerSaved && Number(innerSaved.value) === 1) {
|
|
239
|
+
savedWithToggledExperiments = true;
|
|
240
|
+
}
|
|
241
|
+
for (const [name, meta] of expChildren.entries()) {
|
|
242
|
+
if (meta.type === TAG_BYTE) {
|
|
243
|
+
const num = Number(meta.value);
|
|
244
|
+
experiments[name] = num;
|
|
245
|
+
if (name === "gametest" && num === 1) {
|
|
246
|
+
hasBetaApis = true;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
const knownExperiments = {};
|
|
252
|
+
for (const def of KNOWN_EXPERIMENTS) {
|
|
253
|
+
let enabled = false;
|
|
254
|
+
if (def.isRootTag) {
|
|
255
|
+
const rootTag = parsed.rootChildren.get(def.nbtKey);
|
|
256
|
+
if (rootTag && Number(rootTag.value) === 1) {
|
|
257
|
+
enabled = true;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
const keysToCheck = [def.nbtKey, ...def.aliases ?? []];
|
|
261
|
+
for (const k of keysToCheck) {
|
|
262
|
+
if (experiments[k] === 1) {
|
|
263
|
+
enabled = true;
|
|
264
|
+
break;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
knownExperiments[def.id] = enabled;
|
|
268
|
+
}
|
|
269
|
+
return {
|
|
270
|
+
experimentsEverUsed,
|
|
271
|
+
savedWithToggledExperiments,
|
|
272
|
+
experiments,
|
|
273
|
+
hasBetaApis,
|
|
274
|
+
knownExperiments
|
|
275
|
+
};
|
|
276
|
+
} catch {
|
|
277
|
+
return null;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
function createByteTagBuffer(name, value) {
|
|
281
|
+
const nameBuf = Buffer.from(name, "utf8");
|
|
282
|
+
const buf = Buffer.alloc(1 + 2 + nameBuf.length + 1);
|
|
283
|
+
buf.writeUInt8(TAG_BYTE, 0);
|
|
284
|
+
buf.writeUInt16LE(nameBuf.length, 1);
|
|
285
|
+
nameBuf.copy(buf, 3);
|
|
286
|
+
buf.writeInt8(value, 3 + nameBuf.length);
|
|
287
|
+
return buf;
|
|
288
|
+
}
|
|
289
|
+
function createCompoundTagBuffer(name, byteTags) {
|
|
290
|
+
const nameBuf = Buffer.from(name, "utf8");
|
|
291
|
+
const childBuffers = [];
|
|
292
|
+
for (const [k, v] of Object.entries(byteTags)) {
|
|
293
|
+
childBuffers.push(createByteTagBuffer(k, v));
|
|
294
|
+
}
|
|
295
|
+
childBuffers.push(Buffer.from([TAG_END]));
|
|
296
|
+
const header = Buffer.alloc(1 + 2 + nameBuf.length);
|
|
297
|
+
header.writeUInt8(TAG_COMPOUND, 0);
|
|
298
|
+
header.writeUInt16LE(nameBuf.length, 1);
|
|
299
|
+
nameBuf.copy(header, 3);
|
|
300
|
+
return Buffer.concat([header, ...childBuffers]);
|
|
301
|
+
}
|
|
302
|
+
async function enableExperimentsInLevelDat(levelDatPath, targetExperimentIds) {
|
|
303
|
+
if (!fs.existsSync(levelDatPath)) {
|
|
304
|
+
return { success: false, changed: false, error: `File not found: ${levelDatPath}` };
|
|
305
|
+
}
|
|
306
|
+
try {
|
|
307
|
+
const raw = await fs.promises.readFile(levelDatPath);
|
|
308
|
+
const parsed = parseBedrockLevelDat(raw);
|
|
309
|
+
let targetDefs = [];
|
|
310
|
+
if (!targetExperimentIds || targetExperimentIds === "all") {
|
|
311
|
+
targetDefs = [...KNOWN_EXPERIMENTS];
|
|
312
|
+
} else {
|
|
313
|
+
const seen = /* @__PURE__ */ new Set();
|
|
314
|
+
for (const id of targetExperimentIds) {
|
|
315
|
+
const def = resolveExperimentDefinition(id);
|
|
316
|
+
if (def && !seen.has(def.id)) {
|
|
317
|
+
seen.add(def.id);
|
|
318
|
+
targetDefs.push(def);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
if (targetDefs.length === 0) {
|
|
322
|
+
return { success: true, changed: false, enabledExperiments: [] };
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
const expCompoundTag = parsed.rootChildren.get("experiments");
|
|
326
|
+
const existingExpChildren = expCompoundTag && expCompoundTag.type === TAG_COMPOUND ? parseCompoundChildren(raw, expCompoundTag.valueOffset).children : /* @__PURE__ */ new Map();
|
|
327
|
+
let needsChange = false;
|
|
328
|
+
const enabledIds = [];
|
|
329
|
+
if (!expCompoundTag) {
|
|
330
|
+
needsChange = true;
|
|
331
|
+
} else {
|
|
332
|
+
const expEverUsed = existingExpChildren.get("experiments_ever_used");
|
|
333
|
+
if (!expEverUsed || Number(expEverUsed.value) !== 1) needsChange = true;
|
|
334
|
+
const expSaved = existingExpChildren.get("saved_with_toggled_experiments");
|
|
335
|
+
if (!expSaved || Number(expSaved.value) !== 1) needsChange = true;
|
|
336
|
+
}
|
|
337
|
+
const rootEverUsed = parsed.rootChildren.get("experiments_ever_used");
|
|
338
|
+
if (rootEverUsed && Number(rootEverUsed.value) !== 1) needsChange = true;
|
|
339
|
+
const rootSaved = parsed.rootChildren.get("saved_with_toggled_experiments");
|
|
340
|
+
if (rootSaved && Number(rootSaved.value) !== 1) needsChange = true;
|
|
341
|
+
let previousBetaApisState = false;
|
|
342
|
+
const currentGametest = existingExpChildren.get("gametest");
|
|
343
|
+
if (currentGametest && Number(currentGametest.value) === 1) {
|
|
344
|
+
previousBetaApisState = true;
|
|
345
|
+
}
|
|
346
|
+
for (const def of targetDefs) {
|
|
347
|
+
enabledIds.push(def.id);
|
|
348
|
+
if (def.isRootTag) {
|
|
349
|
+
const rootTag = parsed.rootChildren.get(def.nbtKey);
|
|
350
|
+
if (!rootTag || Number(rootTag.value) !== 1) {
|
|
351
|
+
needsChange = true;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
if (!def.isRootTag) {
|
|
355
|
+
const tag = existingExpChildren.get(def.nbtKey);
|
|
356
|
+
if (!tag || Number(tag.value) !== 1) {
|
|
357
|
+
needsChange = true;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
if (def.extraExpTags) {
|
|
361
|
+
for (const extra of def.extraExpTags) {
|
|
362
|
+
const tag = existingExpChildren.get(extra);
|
|
363
|
+
if (!tag || Number(tag.value) !== 1) {
|
|
364
|
+
needsChange = true;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
if (!needsChange) {
|
|
370
|
+
return {
|
|
371
|
+
success: true,
|
|
372
|
+
changed: false,
|
|
373
|
+
previousBetaApisState,
|
|
374
|
+
enabledExperiments: enabledIds
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
const backupPath = `${levelDatPath}.bak`;
|
|
378
|
+
await fs.promises.copyFile(levelDatPath, backupPath);
|
|
379
|
+
let mutatedRaw = Buffer.from(raw);
|
|
380
|
+
let nbtBody;
|
|
381
|
+
const requiredExpTags = {
|
|
382
|
+
experiments_ever_used: 1,
|
|
383
|
+
saved_with_toggled_experiments: 1
|
|
384
|
+
};
|
|
385
|
+
for (const def of targetDefs) {
|
|
386
|
+
if (!def.isRootTag) {
|
|
387
|
+
requiredExpTags[def.nbtKey] = 1;
|
|
388
|
+
}
|
|
389
|
+
if (def.extraExpTags) {
|
|
390
|
+
for (const extra of def.extraExpTags) {
|
|
391
|
+
requiredExpTags[extra] = 1;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
const rootNeedsEducation = targetDefs.some((d) => d.id === "education");
|
|
396
|
+
if (rootEverUsed) {
|
|
397
|
+
mutatedRaw.writeInt8(1, rootEverUsed.valueOffset);
|
|
398
|
+
}
|
|
399
|
+
if (rootSaved) {
|
|
400
|
+
mutatedRaw.writeInt8(1, rootSaved.valueOffset);
|
|
401
|
+
}
|
|
402
|
+
if (rootNeedsEducation) {
|
|
403
|
+
const eduTag = parsed.rootChildren.get("educationFeaturesEnabled");
|
|
404
|
+
if (eduTag) {
|
|
405
|
+
mutatedRaw.writeInt8(1, eduTag.valueOffset);
|
|
406
|
+
}
|
|
407
|
+
const optOut = parsed.rootChildren.get("has_opted_out_of_education");
|
|
408
|
+
if (optOut) {
|
|
409
|
+
mutatedRaw.writeInt8(0, optOut.valueOffset);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
const rootTagsToAppend = [];
|
|
413
|
+
if (rootNeedsEducation && !parsed.rootChildren.has("educationFeaturesEnabled")) {
|
|
414
|
+
rootTagsToAppend.push(createByteTagBuffer("educationFeaturesEnabled", 1));
|
|
415
|
+
}
|
|
416
|
+
if (!expCompoundTag) {
|
|
417
|
+
const newExpCompoundBuf = createCompoundTagBuffer("experiments", requiredExpTags);
|
|
418
|
+
const rootEndTagIndex = parsed.rootEndOffset - 1;
|
|
419
|
+
const beforeEnd = mutatedRaw.subarray(8, rootEndTagIndex);
|
|
420
|
+
const afterEnd = mutatedRaw.subarray(rootEndTagIndex);
|
|
421
|
+
nbtBody = Buffer.concat([beforeEnd, ...rootTagsToAppend, newExpCompoundBuf, afterEnd]);
|
|
422
|
+
} else {
|
|
423
|
+
const { compoundEndOffset: expEndOffset } = parseCompoundChildren(raw, expCompoundTag.valueOffset);
|
|
424
|
+
const expEndTagIndex = expEndOffset - 1;
|
|
425
|
+
const rootEndTagIndex = parsed.rootEndOffset - 1;
|
|
426
|
+
const expTagsToAppend = [];
|
|
427
|
+
for (const [name, val] of Object.entries(requiredExpTags)) {
|
|
428
|
+
const existing = existingExpChildren.get(name);
|
|
429
|
+
if (existing) {
|
|
430
|
+
mutatedRaw.writeInt8(val, existing.valueOffset);
|
|
431
|
+
} else {
|
|
432
|
+
expTagsToAppend.push(createByteTagBuffer(name, val));
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
const part1 = mutatedRaw.subarray(8, expEndTagIndex);
|
|
436
|
+
const part2 = Buffer.concat(expTagsToAppend);
|
|
437
|
+
const part3 = mutatedRaw.subarray(expEndTagIndex, rootEndTagIndex);
|
|
438
|
+
const part4 = Buffer.concat(rootTagsToAppend);
|
|
439
|
+
const part5 = mutatedRaw.subarray(rootEndTagIndex);
|
|
440
|
+
nbtBody = Buffer.concat([part1, part2, part3, part4, part5]);
|
|
441
|
+
}
|
|
442
|
+
const newHeader = Buffer.alloc(8);
|
|
443
|
+
newHeader.writeUInt32LE(parsed.version, 0);
|
|
444
|
+
newHeader.writeUInt32LE(nbtBody.length, 4);
|
|
445
|
+
const finalFileBuffer = Buffer.concat([newHeader, nbtBody]);
|
|
446
|
+
const tmpFile = `${levelDatPath}.${process.pid}.tmp`;
|
|
447
|
+
await fs.promises.writeFile(tmpFile, finalFileBuffer);
|
|
448
|
+
await fs.promises.rename(tmpFile, levelDatPath);
|
|
449
|
+
return {
|
|
450
|
+
success: true,
|
|
451
|
+
changed: true,
|
|
452
|
+
backupPath,
|
|
453
|
+
previousBetaApisState,
|
|
454
|
+
enabledExperiments: enabledIds
|
|
455
|
+
};
|
|
456
|
+
} catch (err) {
|
|
457
|
+
return {
|
|
458
|
+
success: false,
|
|
459
|
+
changed: false,
|
|
460
|
+
error: err instanceof Error ? err.message : String(err)
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
async function enableBetaApisInLevelDat(levelDatPath) {
|
|
465
|
+
return await enableExperimentsInLevelDat(levelDatPath, ["gametest"]);
|
|
466
|
+
}
|
|
467
|
+
export {
|
|
468
|
+
KNOWN_EXPERIMENTS,
|
|
469
|
+
TAG_BYTE,
|
|
470
|
+
TAG_BYTE_ARRAY,
|
|
471
|
+
TAG_COMPOUND,
|
|
472
|
+
TAG_DOUBLE,
|
|
473
|
+
TAG_END,
|
|
474
|
+
TAG_FLOAT,
|
|
475
|
+
TAG_INT,
|
|
476
|
+
TAG_INT_ARRAY,
|
|
477
|
+
TAG_LIST,
|
|
478
|
+
TAG_LONG,
|
|
479
|
+
TAG_LONG_ARRAY,
|
|
480
|
+
TAG_SHORT,
|
|
481
|
+
TAG_STRING,
|
|
482
|
+
enableBetaApisInLevelDat,
|
|
483
|
+
enableExperimentsInLevelDat,
|
|
484
|
+
parseBedrockLevelDat,
|
|
485
|
+
parseCompoundChildren,
|
|
486
|
+
readLevelDatExperiments,
|
|
487
|
+
resolveExperimentDefinition,
|
|
488
|
+
skipNbtPayload
|
|
489
|
+
};
|
|
490
|
+
//# sourceMappingURL=level-dat.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/level-dat.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * level-dat.ts \u2014 Minecraft \u57FA\u5CA9\u7248\u4E16\u754C\u5B58\u6863 level.dat \u5C0F\u7AEF\u5E8F NBT \u89E3\u6790\u4E0E\u5B9E\u9A8C\u6027\u73A9\u6CD5\u5B89\u5168\u4FEE\u6539\u5668\n *\n * \u57FA\u5CA9\u7248 level.dat \u89C4\u8303\uFF1A\n * - Header\uFF088 \u5B57\u8282\uFF09\uFF1A\n * - [0..3] uint32 LE\uFF1A\u5B58\u50A8\u683C\u5F0F\u7248\u672C\uFF08\u5F53\u524D\u7248\u672C\u901A\u5E38\u4E3A 10\uFF09\n * - [4..7] uint32 LE\uFF1A\u6709\u6548 NBT \u6570\u636E\u5B57\u8282\u957F\u5EA6\uFF08data_length\uFF09\n * - Payload\uFF1A\u672A\u538B\u7F29\u7684\u5C0F\u7AEF\u5E8F\uFF08Little-Endian\uFF09\u6807\u51C6 NBT \u590D\u5408\u6807\u7B7E\uFF08TAG_Compound\uFF09\n *\n * \u6838\u5FC3\u80FD\u529B\uFF1A\n * - \u539F\u751F\u65E0\u5916\u90E8\u9ED1\u76D2\u4F9D\u8D56\uFF0CBuffer \u7EA7\u89E3\u6790\u4E0E\u7CBE\u786E\u5B57\u8282\u4F4D\u79FB\n * - \u8BFB\u53D6\u4E16\u754C\u5B9E\u9A8C\u6027\u73A9\u6CD5\u7684\u5F00\u542F\u72B6\u6001\uFF08\u7279\u522B\u662F Beta APIs / gametest\uFF09\n * - \u5B89\u5168\u6CE8\u5165\u6216\u5207\u6362\u5B9E\u9A8C\u6027\u5F00\u5173\u5E76\u81EA\u52A8\u5907\u4EFD\u539F\u6587\u4EF6\uFF08.bak\uFF09\u4E0E\u6821\u51C6 Header data_length\n */\n\nimport fs from \"node:fs\";\n\nexport const TAG_END = 0;\nexport const TAG_BYTE = 1;\nexport const TAG_SHORT = 2;\nexport const TAG_INT = 3;\nexport const TAG_LONG = 4;\nexport const TAG_FLOAT = 5;\nexport const TAG_DOUBLE = 6;\nexport const TAG_BYTE_ARRAY = 7;\nexport const TAG_STRING = 8;\nexport const TAG_LIST = 9;\nexport const TAG_COMPOUND = 10;\nexport const TAG_INT_ARRAY = 11;\nexport const TAG_LONG_ARRAY = 12;\n\nexport interface NbtTagMeta {\n type: number;\n name: string;\n startOffset: number; // \u5305\u542B tagType \u7684\u8D77\u59CB\u7EDD\u5BF9 offset\n nameOffset: number; // \u6807\u7B7E\u540D\u79F0\u8D77\u59CB offset\n valueOffset: number; // \u8F7D\u8377\u8D77\u59CB offset\n endOffset: number; // \u6807\u7B7E\u7ED3\u675F\u7EDD\u5BF9 offset\n value?: unknown;\n}\n\nexport interface KnownExperimentDefinition {\n id: string;\n nbtKey: string;\n nameZh: string;\n nameEn: string;\n aliases?: string[];\n isRootTag?: boolean;\n extraExpTags?: string[];\n}\n\nexport const KNOWN_EXPERIMENTS: readonly KnownExperimentDefinition[] = [\n {\n id: \"gametest\",\n nbtKey: \"gametest\",\n nameZh: \"\u6D4B\u8BD5\u7248 API\",\n nameEn: \"Beta APIs (gametest)\",\n aliases: [\"beta\", \"beta_apis\", \"betapis\", \"gametest\"],\n },\n {\n id: \"upcoming_creator_features\",\n nbtKey: \"upcoming_creator_features\",\n nameZh: \"\u5373\u5C06\u63A8\u51FA\u7684\u521B\u4F5C\u8005\u529F\u80FD\",\n nameEn: \"Upcoming Creator Features\",\n aliases: [\"upcoming\", \"creator_features\", \"upcoming_features\"],\n },\n {\n id: \"experimental_creator_cameras\",\n nbtKey: \"experimental_creator_cameras\",\n nameZh: \"\u521B\u5EFA\u8005\u7167\u76F8\u673A\u7684\u5B9E\u9A8C\u6027\u529F\u80FD\",\n nameEn: \"Experimental Creator Cameras\",\n aliases: [\"camera\", \"cameras\", \"creator_cameras\", \"creator_camera\"],\n },\n {\n id: \"voxel_shapes\",\n nbtKey: \"voxel_shapes\",\n nameZh: \"\u5B9E\u9A8C\u6027Voxel\u5F62\u72B6\u7279\u5F81\",\n nameEn: \"Experimental Voxel Shapes\",\n aliases: [\"voxel\", \"voxel_shape\", \"experimental_voxel_shapes\", \"voxelshapes\"],\n },\n {\n id: \"villager_trades_rebalance\",\n nbtKey: \"villager_trades_rebalance\",\n nameZh: \"\u6751\u6C11\u8D38\u6613\u518D\u5E73\u8861\",\n nameEn: \"Villager Trade Rebalance\",\n aliases: [\"villager\", \"trades\", \"villager_trades\", \"trade_rebalance\"],\n },\n {\n id: \"drop_3_2026\",\n nbtKey: \"drop_3_2026\",\n nameZh: \"2026\u5E74\u7B2C3\u6B21\u66F4\u65B0\",\n nameEn: \"Drop 3 of 2026\",\n aliases: [\n \"drop3\",\n \"drop_3\",\n \"drop_3_2026\",\n \"wilderness\",\n \"wilderness_bound\",\n \"update_2026_drop_3\",\n \"update_26_3\",\n \"update_drop_3\",\n ],\n extraExpTags: [\"update_2026_drop_3\"],\n },\n {\n id: \"education\",\n nbtKey: \"educationFeaturesEnabled\",\n nameZh: \"Minecraft Education \u529F\u80FD\",\n nameEn: \"Minecraft Education Features\",\n isRootTag: true,\n aliases: [\"edu\", \"education\", \"education_edition\", \"educationfeatures\"],\n extraExpTags: [\"education\"],\n },\n] as const;\n\nexport function resolveExperimentDefinition(query: string): KnownExperimentDefinition | null {\n const q = query.trim().toLowerCase().replace(/[-_]/g, \"\");\n for (const def of KNOWN_EXPERIMENTS) {\n if (def.id.replace(/[-_]/g, \"\") === q) return def;\n if (def.nbtKey.replace(/[-_]/g, \"\") === q) return def;\n if (def.aliases) {\n for (const a of def.aliases) {\n if (a.replace(/[-_]/g, \"\") === q) return def;\n }\n }\n }\n return null;\n}\n\nexport interface LevelDatExperimentsInfo {\n experimentsEverUsed: boolean;\n savedWithToggledExperiments: boolean;\n experiments: Record<string, number | boolean>;\n hasBetaApis: boolean;\n knownExperiments: Record<string, boolean>;\n}\n\nexport interface LevelDatMutateResult {\n success: boolean;\n changed: boolean;\n backupPath?: string;\n error?: string;\n previousBetaApisState?: boolean;\n enabledExperiments?: string[];\n}\n\n/**\n * \u904D\u5386\u5E76\u8DF3\u8FC7\u6307\u5B9A\u7C7B\u578B\u7684 NBT \u8F7D\u8377\uFF0C\u8FD4\u56DE\u4E0B\u4E00\u4E2A tag \u7684 offset\u3002\n */\nexport function skipNbtPayload(buf: Buffer, offset: number, type: number): number {\n switch (type) {\n case TAG_BYTE:\n return offset + 1;\n case TAG_SHORT:\n return offset + 2;\n case TAG_INT:\n case TAG_FLOAT:\n return offset + 4;\n case TAG_LONG:\n case TAG_DOUBLE:\n return offset + 8;\n case TAG_BYTE_ARRAY: {\n if (offset + 4 > buf.length) throw new Error(\"Unexpected EOF reading TAG_Byte_Array length\");\n const len = buf.readInt32LE(offset);\n return offset + 4 + Math.max(0, len);\n }\n case TAG_STRING: {\n if (offset + 2 > buf.length) throw new Error(\"Unexpected EOF reading TAG_String length\");\n const len = buf.readUInt16LE(offset);\n return offset + 2 + len;\n }\n case TAG_LIST: {\n if (offset + 5 > buf.length) throw new Error(\"Unexpected EOF reading TAG_List header\");\n const elemType = buf.readUInt8(offset);\n const count = buf.readInt32LE(offset + 1);\n let cur = offset + 5;\n for (let i = 0; i < count; i++) {\n cur = skipNbtPayload(buf, cur, elemType);\n }\n return cur;\n }\n case TAG_COMPOUND: {\n let cur = offset;\n while (cur < buf.length) {\n const t = buf.readUInt8(cur);\n if (t === TAG_END) {\n return cur + 1;\n }\n if (cur + 3 > buf.length) throw new Error(\"Unexpected EOF reading compound child header\");\n const nameLen = buf.readUInt16LE(cur + 1);\n const childValOffset = cur + 3 + nameLen;\n cur = skipNbtPayload(buf, childValOffset, t);\n }\n return cur;\n }\n case TAG_INT_ARRAY: {\n if (offset + 4 > buf.length) throw new Error(\"Unexpected EOF reading TAG_Int_Array length\");\n const len = buf.readInt32LE(offset);\n return offset + 4 + Math.max(0, len) * 4;\n }\n case TAG_LONG_ARRAY: {\n if (offset + 4 > buf.length) throw new Error(\"Unexpected EOF reading TAG_Long_Array length\");\n const len = buf.readInt32LE(offset);\n return offset + 4 + Math.max(0, len) * 8;\n }\n default:\n throw new Error(`Unsupported or unknown NBT tag type: ${type} at offset ${offset}`);\n }\n}\n\n/**\n * \u89E3\u6790\u590D\u5408\u6807\u7B7E\u5185\u90E8\u6240\u6709\u76F4\u63A5\u5B50\u6807\u7B7E\u7684\u5143\u6570\u636E\u6620\u5C04\u3002\n */\nexport function parseCompoundChildren(\n buf: Buffer,\n compoundValueOffset: number\n): { children: Map<string, NbtTagMeta>; compoundEndOffset: number } {\n const children = new Map<string, NbtTagMeta>();\n let cur = compoundValueOffset;\n\n while (cur < buf.length) {\n const tagType = buf.readUInt8(cur);\n if (tagType === TAG_END) {\n return { children, compoundEndOffset: cur + 1 };\n }\n if (cur + 3 > buf.length) {\n throw new Error(`Unexpected EOF reading named tag header at offset ${cur}`);\n }\n const nameLen = buf.readUInt16LE(cur + 1);\n const nameOffset = cur + 3;\n if (nameOffset + nameLen > buf.length) {\n throw new Error(`Unexpected EOF reading tag name at offset ${cur}`);\n }\n const name = buf.toString(\"utf8\", nameOffset, nameOffset + nameLen);\n const valOffset = nameOffset + nameLen;\n const endOffset = skipNbtPayload(buf, valOffset, tagType);\n\n let val: unknown = undefined;\n if (tagType === TAG_BYTE) {\n val = buf.readInt8(valOffset);\n } else if (tagType === TAG_INT) {\n val = buf.readInt32LE(valOffset);\n } else if (tagType === TAG_STRING) {\n const sLen = buf.readUInt16LE(valOffset);\n val = buf.toString(\"utf8\", valOffset + 2, valOffset + 2 + sLen);\n }\n\n children.set(name, {\n type: tagType,\n name,\n startOffset: cur,\n nameOffset,\n valueOffset: valOffset,\n endOffset,\n value: val,\n });\n\n cur = endOffset;\n }\n\n return { children, compoundEndOffset: cur };\n}\n\n/**\n * \u89E3\u6790\u57FA\u5CA9\u7248 level.dat \u7684\u5B8C\u6574\u6587\u4EF6\u7ED3\u6784\u5E76\u5B9A\u4F4D\u6839 Compound\u3002\n */\nexport function parseBedrockLevelDat(buf: Buffer): {\n version: number;\n dataLength: number;\n rootCompoundName: string;\n rootChildren: Map<string, NbtTagMeta>;\n rootEndOffset: number;\n} {\n if (buf.length < 8) {\n throw new Error(\"Invalid level.dat: buffer smaller than 8-byte header\");\n }\n const version = buf.readUInt32LE(0);\n const dataLength = buf.readUInt32LE(4);\n\n // \u6839\u6807\u7B7E\u5FC5\u987B\u662F TAG_Compound\n if (buf.length < 9 || buf.readUInt8(8) !== TAG_COMPOUND) {\n throw new Error(\"Invalid level.dat: root tag is not TAG_Compound\");\n }\n const rootNameLen = buf.readUInt16LE(9);\n const rootCompoundName = buf.toString(\"utf8\", 11, 11 + rootNameLen);\n const rootValueOffset = 11 + rootNameLen;\n\n const { children: rootChildren, compoundEndOffset: rootEndOffset } = parseCompoundChildren(buf, rootValueOffset);\n\n return {\n version,\n dataLength,\n rootCompoundName,\n rootChildren,\n rootEndOffset,\n };\n}\n\n/**\n * \u8BFB\u53D6\u4E16\u754C\u5B58\u6863 level.dat \u7684\u5B9E\u9A8C\u6027\u914D\u7F6E\u3002\u82E5\u89E3\u6790\u5931\u8D25\u6216\u6587\u4EF6\u4E0D\u5B58\u5728\u8FD4\u56DE null\u3002\n */\nexport function readLevelDatExperiments(levelDatPath: string): LevelDatExperimentsInfo | null {\n if (!fs.existsSync(levelDatPath)) return null;\n try {\n const buf = fs.readFileSync(levelDatPath);\n const parsed = parseBedrockLevelDat(buf);\n\n let experimentsEverUsed = false;\n const everUsedTag = parsed.rootChildren.get(\"experiments_ever_used\");\n if (everUsedTag && everUsedTag.type === TAG_BYTE && Number(everUsedTag.value) === 1) {\n experimentsEverUsed = true;\n }\n\n let savedWithToggledExperiments = false;\n const savedTag = parsed.rootChildren.get(\"saved_with_toggled_experiments\");\n if (savedTag && savedTag.type === TAG_BYTE && Number(savedTag.value) === 1) {\n savedWithToggledExperiments = true;\n }\n\n const experiments: Record<string, number | boolean> = {};\n let hasBetaApis = false;\n\n const expCompoundTag = parsed.rootChildren.get(\"experiments\");\n if (expCompoundTag && expCompoundTag.type === TAG_COMPOUND) {\n const expChildren = parseCompoundChildren(buf, expCompoundTag.valueOffset).children;\n\n // \u90E8\u5206\u7248\u672C experiments_ever_used \u4E5F\u53EF\u80FD\u4F4D\u4E8E experiments \u5185\u90E8\n const innerEverUsed = expChildren.get(\"experiments_ever_used\");\n if (innerEverUsed && Number(innerEverUsed.value) === 1) {\n experimentsEverUsed = true;\n }\n const innerSaved = expChildren.get(\"saved_with_toggled_experiments\");\n if (innerSaved && Number(innerSaved.value) === 1) {\n savedWithToggledExperiments = true;\n }\n\n for (const [name, meta] of expChildren.entries()) {\n if (meta.type === TAG_BYTE) {\n const num = Number(meta.value);\n experiments[name] = num;\n if (name === \"gametest\" && num === 1) {\n hasBetaApis = true;\n }\n }\n }\n }\n\n const knownExperiments: Record<string, boolean> = {};\n for (const def of KNOWN_EXPERIMENTS) {\n let enabled = false;\n if (def.isRootTag) {\n const rootTag = parsed.rootChildren.get(def.nbtKey);\n if (rootTag && Number(rootTag.value) === 1) {\n enabled = true;\n }\n }\n const keysToCheck = [def.nbtKey, ...(def.aliases ?? [])];\n for (const k of keysToCheck) {\n if (experiments[k] === 1) {\n enabled = true;\n break;\n }\n }\n knownExperiments[def.id] = enabled;\n }\n\n return {\n experimentsEverUsed,\n savedWithToggledExperiments,\n experiments,\n hasBetaApis,\n knownExperiments,\n };\n } catch {\n return null;\n }\n}\n\n/**\n * \u6784\u9020\u4E00\u4E2A TAG_Byte \u7684\u4E8C\u8FDB\u5236 Buffer\u3002\n */\nfunction createByteTagBuffer(name: string, value: number): Buffer {\n const nameBuf = Buffer.from(name, \"utf8\");\n const buf = Buffer.alloc(1 + 2 + nameBuf.length + 1);\n buf.writeUInt8(TAG_BYTE, 0);\n buf.writeUInt16LE(nameBuf.length, 1);\n nameBuf.copy(buf, 3);\n buf.writeInt8(value, 3 + nameBuf.length);\n return buf;\n}\n\n/**\n * \u6784\u9020\u4E00\u4E2A\u5305\u542B\u6307\u5B9A\u952E\u503C\u5BF9\u7684 TAG_Compound Buffer\u3002\n */\nfunction createCompoundTagBuffer(name: string, byteTags: Record<string, number>): Buffer {\n const nameBuf = Buffer.from(name, \"utf8\");\n const childBuffers: Buffer[] = [];\n for (const [k, v] of Object.entries(byteTags)) {\n childBuffers.push(createByteTagBuffer(k, v));\n }\n childBuffers.push(Buffer.from([TAG_END]));\n\n const header = Buffer.alloc(1 + 2 + nameBuf.length);\n header.writeUInt8(TAG_COMPOUND, 0);\n header.writeUInt16LE(nameBuf.length, 1);\n nameBuf.copy(header, 3);\n\n return Buffer.concat([header, ...childBuffers]);\n}\n\n/**\n * \u4E3A\u6307\u5B9A level.dat \u5F00\u542F\u6307\u5B9A\u7684\u5B9E\u9A8C\u6027\u5F00\u5173\uFF08\u82E5\u672A\u6307\u5B9A\u6216\u4F20 \"all\" \u5219\u5F00\u542F\u5168\u90E8\u5DF2\u77E5\u5B9E\u9A8C\u6027\u5F00\u5173\uFF09\u3002\n *\n * \u4FDD\u8BC1\uFF1A\n * - \u81EA\u52A8\u5907\u4EFD\u539F\u6587\u4EF6\u81F3 `${levelDatPath}.bak`\uFF1B\n * - \u81EA\u52A8\u66F4\u65B0 root \u4E0E experiments \u590D\u5408\u6807\u7B7E\u4E2D\u7684\u76EE\u6807 byte tags\uFF1B\n * - \u81EA\u52A8\u66F4\u65B0 experiments_ever_used = 1b \u4E0E saved_with_toggled_experiments = 1b\uFF1B\n * - \u7CBE\u786E\u6821\u51C6 8 \u5B57\u8282\u6587\u4EF6\u5934\u90E8\u7684 dataLength\uFF1B\n * - \u539F\u5B50\u5199\u64CD\u4F5C\uFF08.tmp -> rename\uFF09\uFF1B\n * - \u82E5\u6240\u8BF7\u6C42\u5F00\u5173\u5DF2\u5168\u90E8\u5904\u4E8E\u5F00\u542F\u72B6\u6001\uFF0C\u76F4\u63A5\u8FD4\u56DE changed: false\uFF0C\u4E0D\u7834\u574F\u6587\u4EF6\u3002\n */\nexport async function enableExperimentsInLevelDat(\n levelDatPath: string,\n targetExperimentIds?: string[] | \"all\"\n): Promise<LevelDatMutateResult> {\n if (!fs.existsSync(levelDatPath)) {\n return { success: false, changed: false, error: `File not found: ${levelDatPath}` };\n }\n\n try {\n const raw = await fs.promises.readFile(levelDatPath);\n const parsed = parseBedrockLevelDat(raw);\n\n // \u89E3\u6790\u76EE\u6807\u5B9E\u9A8C\u9879\n let targetDefs: KnownExperimentDefinition[] = [];\n if (!targetExperimentIds || targetExperimentIds === \"all\") {\n targetDefs = [...KNOWN_EXPERIMENTS];\n } else {\n const seen = new Set<string>();\n for (const id of targetExperimentIds) {\n const def = resolveExperimentDefinition(id);\n if (def && !seen.has(def.id)) {\n seen.add(def.id);\n targetDefs.push(def);\n }\n }\n if (targetDefs.length === 0) {\n return { success: true, changed: false, enabledExperiments: [] };\n }\n }\n\n const expCompoundTag = parsed.rootChildren.get(\"experiments\");\n const existingExpChildren =\n expCompoundTag && expCompoundTag.type === TAG_COMPOUND\n ? parseCompoundChildren(raw, expCompoundTag.valueOffset).children\n : new Map<string, NbtTagMeta>();\n\n // \u68C0\u67E5\u5F53\u524D\u72B6\u6001\n let needsChange = false;\n const enabledIds: string[] = [];\n\n // 1. \u68C0\u67E5 experiments compound \u53CA\u5185\u90E8\u5FC5\u8981\u7CFB\u7EDF\u6807\u7B7E\n if (!expCompoundTag) {\n needsChange = true;\n } else {\n const expEverUsed = existingExpChildren.get(\"experiments_ever_used\");\n if (!expEverUsed || Number(expEverUsed.value) !== 1) needsChange = true;\n\n const expSaved = existingExpChildren.get(\"saved_with_toggled_experiments\");\n if (!expSaved || Number(expSaved.value) !== 1) needsChange = true;\n }\n\n // \u82E5 root \u5C42\u5B58\u5728\u7CFB\u7EDF\u6807\u7B7E\u4F46\u672A\u8BBE\u4E3A 1\uFF0C\u4E5F\u9700\u4FEE\u6B63\n const rootEverUsed = parsed.rootChildren.get(\"experiments_ever_used\");\n if (rootEverUsed && Number(rootEverUsed.value) !== 1) needsChange = true;\n\n const rootSaved = parsed.rootChildren.get(\"saved_with_toggled_experiments\");\n if (rootSaved && Number(rootSaved.value) !== 1) needsChange = true;\n\n let previousBetaApisState = false;\n const currentGametest = existingExpChildren.get(\"gametest\");\n if (currentGametest && Number(currentGametest.value) === 1) {\n previousBetaApisState = true;\n }\n\n for (const def of targetDefs) {\n enabledIds.push(def.id);\n if (def.isRootTag) {\n const rootTag = parsed.rootChildren.get(def.nbtKey);\n if (!rootTag || Number(rootTag.value) !== 1) {\n needsChange = true;\n }\n }\n if (!def.isRootTag) {\n const tag = existingExpChildren.get(def.nbtKey);\n if (!tag || Number(tag.value) !== 1) {\n needsChange = true;\n }\n }\n if (def.extraExpTags) {\n for (const extra of def.extraExpTags) {\n const tag = existingExpChildren.get(extra);\n if (!tag || Number(tag.value) !== 1) {\n needsChange = true;\n }\n }\n }\n }\n\n if (!needsChange) {\n return {\n success: true,\n changed: false,\n previousBetaApisState,\n enabledExperiments: enabledIds,\n };\n }\n\n // \u5907\u4EFD\u539F\u6587\u4EF6\n const backupPath = `${levelDatPath}.bak`;\n await fs.promises.copyFile(levelDatPath, backupPath);\n\n let mutatedRaw = Buffer.from(raw);\n let nbtBody: Buffer;\n\n // \u6536\u96C6\u9700\u8981\u5728 experiments \u590D\u5408\u6807\u7B7E\u4E2D\u8BBE\u7F6E\u7684 tags\n const requiredExpTags: Record<string, number> = {\n experiments_ever_used: 1,\n saved_with_toggled_experiments: 1,\n };\n for (const def of targetDefs) {\n if (!def.isRootTag) {\n requiredExpTags[def.nbtKey] = 1;\n }\n if (def.extraExpTags) {\n for (const extra of def.extraExpTags) {\n requiredExpTags[extra] = 1;\n }\n }\n }\n\n // \u6536\u96C6 root \u5C42\u9700\u8981\u66F4\u65B0\u6216\u63D2\u5165\u7684 tags\n const rootNeedsEducation = targetDefs.some((d) => d.id === \"education\");\n\n // \u66F4\u65B0 root \u5C42\u5DF2\u5B58\u5728\u7684\u76F8\u5173 tags\n if (rootEverUsed) {\n mutatedRaw.writeInt8(1, rootEverUsed.valueOffset);\n }\n if (rootSaved) {\n mutatedRaw.writeInt8(1, rootSaved.valueOffset);\n }\n if (rootNeedsEducation) {\n const eduTag = parsed.rootChildren.get(\"educationFeaturesEnabled\");\n if (eduTag) {\n mutatedRaw.writeInt8(1, eduTag.valueOffset);\n }\n const optOut = parsed.rootChildren.get(\"has_opted_out_of_education\");\n if (optOut) {\n mutatedRaw.writeInt8(0, optOut.valueOffset);\n }\n }\n\n const rootTagsToAppend: Buffer[] = [];\n if (rootNeedsEducation && !parsed.rootChildren.has(\"educationFeaturesEnabled\")) {\n rootTagsToAppend.push(createByteTagBuffer(\"educationFeaturesEnabled\", 1));\n }\n\n if (!expCompoundTag) {\n // \u573A\u666F 1\uFF1A\u5B8C\u5168\u7F3A\u5931 experiments compound\n const newExpCompoundBuf = createCompoundTagBuffer(\"experiments\", requiredExpTags);\n const rootEndTagIndex = parsed.rootEndOffset - 1;\n const beforeEnd = mutatedRaw.subarray(8, rootEndTagIndex);\n const afterEnd = mutatedRaw.subarray(rootEndTagIndex);\n nbtBody = Buffer.concat([beforeEnd, ...rootTagsToAppend, newExpCompoundBuf, afterEnd]);\n } else {\n // \u573A\u666F 2\uFF1A\u5DF2\u6709 experiments compound\n const { compoundEndOffset: expEndOffset } = parseCompoundChildren(raw, expCompoundTag.valueOffset);\n const expEndTagIndex = expEndOffset - 1;\n const rootEndTagIndex = parsed.rootEndOffset - 1;\n\n const expTagsToAppend: Buffer[] = [];\n for (const [name, val] of Object.entries(requiredExpTags)) {\n const existing = existingExpChildren.get(name);\n if (existing) {\n mutatedRaw.writeInt8(val, existing.valueOffset);\n } else {\n expTagsToAppend.push(createByteTagBuffer(name, val));\n }\n }\n\n // \u7EC4\u88C5\u65B0 NBT body\n // Part 1: root \u5F00\u59CB\u5230 experiments TAG_END \u524D\n const part1 = mutatedRaw.subarray(8, expEndTagIndex);\n // Part 2: \u8FFD\u52A0\u5230 experiments \u5185\u90E8\u7684 tags\n const part2 = Buffer.concat(expTagsToAppend);\n // Part 3: experiments TAG_END \u5230 root TAG_END \u524D\n const part3 = mutatedRaw.subarray(expEndTagIndex, rootEndTagIndex);\n // Part 4: \u8FFD\u52A0\u5230 root \u5C42\u7684 tags (\u5982 educationFeaturesEnabled)\n const part4 = Buffer.concat(rootTagsToAppend);\n // Part 5: root TAG_END \u53CA\u540E\u7EED\n const part5 = mutatedRaw.subarray(rootEndTagIndex);\n\n nbtBody = Buffer.concat([part1, part2, part3, part4, part5]);\n }\n\n // \u91CD\u65B0\u6784\u9020 8 \u5B57\u8282 header\n const newHeader = Buffer.alloc(8);\n newHeader.writeUInt32LE(parsed.version, 0);\n newHeader.writeUInt32LE(nbtBody.length, 4);\n\n const finalFileBuffer = Buffer.concat([newHeader, nbtBody]);\n\n // \u539F\u5B50\u66FF\u6362\n const tmpFile = `${levelDatPath}.${process.pid}.tmp`;\n await fs.promises.writeFile(tmpFile, finalFileBuffer);\n await fs.promises.rename(tmpFile, levelDatPath);\n\n return {\n success: true,\n changed: true,\n backupPath,\n previousBetaApisState,\n enabledExperiments: enabledIds,\n };\n } catch (err) {\n return {\n success: false,\n changed: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n}\n\n/**\n * \u4E3A\u6307\u5B9A level.dat \u5F00\u542F Beta APIs\uFF08gametest\uFF09\u3002\n * \u4FDD\u6301\u5411\u540E\u517C\u5BB9\uFF0C\u59D4\u6258\u7ED9 enableExperimentsInLevelDat\u3002\n */\nexport async function enableBetaApisInLevelDat(levelDatPath: string): Promise<LevelDatMutateResult> {\n return await enableExperimentsInLevelDat(levelDatPath, [\"gametest\"]);\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|