@bkm016/calcite 0.1.0 → 0.2.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/README.md +113 -11
- package/dist/accounts.d.ts +23 -4
- package/dist/accounts.js +120 -40
- package/dist/accounts.js.map +1 -1
- package/dist/cli.js +95 -5
- package/dist/cli.js.map +1 -1
- package/dist/client-core.d.ts +66 -0
- package/dist/client-core.js +530 -0
- package/dist/client-core.js.map +1 -0
- package/dist/client.d.ts +86 -210
- package/dist/client.js +90 -576
- package/dist/client.js.map +1 -1
- package/dist/display.js +42 -13
- package/dist/display.js.map +1 -1
- package/dist/hmc.d.ts +31 -11
- package/dist/hmc.js +68 -30
- package/dist/hmc.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js.map +1 -1
- package/dist/install.d.ts +48 -0
- package/dist/install.js +119 -0
- package/dist/install.js.map +1 -0
- package/dist/java.d.ts +8 -2
- package/dist/java.js +14 -10
- package/dist/java.js.map +1 -1
- package/dist/loaders.d.ts +41 -0
- package/dist/loaders.js +86 -0
- package/dist/loaders.js.map +1 -0
- package/dist/mcp.js +128 -3
- package/dist/mcp.js.map +1 -1
- package/dist/mods.d.ts +21 -0
- package/dist/mods.js +135 -0
- package/dist/mods.js.map +1 -0
- package/dist/mojang.d.ts +0 -16
- package/dist/mojang.js +1 -37
- package/dist/mojang.js.map +1 -1
- package/dist/names.d.ts +53 -0
- package/dist/names.js +267 -0
- package/dist/names.js.map +1 -0
- package/dist/net.d.ts +5 -0
- package/dist/net.js +41 -1
- package/dist/net.js.map +1 -1
- package/dist/paths.d.ts +5 -3
- package/dist/paths.js +1 -0
- package/dist/paths.js.map +1 -1
- package/dist/types.d.ts +235 -0
- package/dist/types.js +25 -0
- package/dist/types.js.map +1 -0
- package/dist/zip.d.ts +5 -0
- package/dist/zip.js +65 -0
- package/dist/zip.js.map +1 -0
- package/package.json +1 -1
- package/vendor/calcite-probe.jar +0 -0
package/README.md
CHANGED
|
@@ -28,6 +28,7 @@ Calcite 用于以编程方式驱动**真实的 Minecraft Java 版客户端**。
|
|
|
28
28
|
- [Node.js API](#nodejs-api)
|
|
29
29
|
- [平台与账号](#平台与账号)
|
|
30
30
|
- [渲染模式](#渲染模式)
|
|
31
|
+
- [模组](#模组)
|
|
31
32
|
- [版本兼容性](#版本兼容性)
|
|
32
33
|
- [数据目录与环境变量](#数据目录与环境变量)
|
|
33
34
|
- [故障排查](#故障排查)
|
|
@@ -40,8 +41,10 @@ Calcite 用于以编程方式驱动**真实的 Minecraft Java 版客户端**。
|
|
|
40
41
|
- **跨平台**:Linux、Windows、macOS。
|
|
41
42
|
- **账号**:支持离线账号,也支持微软正版账号。正版账号使用设备码登录,凭据持久保存并自动刷新。
|
|
42
43
|
- **无显卡环境截图**:在 Linux 服务器上通过 Xvfb 与 Mesa 软件渲染完成截图。
|
|
44
|
+
- **模组加载器**:一行参数安装 Fabric、Forge 或 NeoForge,并从本地文件、URL 或 Modrinth 加载模组(自动补全前置依赖),探针功能在模组环境中同样可用。
|
|
45
|
+
- **玩家操作**:转向、移动、寻路到坐标、攻击、使用物品与方块、挖掘、切换快捷栏、丢弃物品,以及打开箱子等容器并点击槽位。操作走原版客户端逻辑,与真实玩家输入等价。
|
|
43
46
|
- **按需渲染**:默认不渲染画面,截图时临时渲染。单次截图约 0.5 秒,进服后首次截图需等待区块编译,约 2–4 秒。
|
|
44
|
-
- **Java 自动管理**:按游戏版本自动选择 Java
|
|
47
|
+
- **Java 自动管理**:按游戏版本自动选择 Java(render `off` 时原本需要 Java 8 的版本改用 Java 17,HeadlessMC 3 的 LWJGL 替身不支持 Java 8);本机缺少时从 Eclipse Adoptium 下载 Temurin,并校验 SHA-256。HeadlessMC 3 本身运行在 Java 25 上,同样按需下载。
|
|
45
48
|
- **自动重连**:掉线或崩溃后按指数退避自动重连。
|
|
46
49
|
- **多客户端**:一个进程可同时管理多个相互隔离的客户端实例。
|
|
47
50
|
|
|
@@ -50,7 +53,7 @@ Calcite 用于以编程方式驱动**真实的 Minecraft Java 版客户端**。
|
|
|
50
53
|
| 项目 | 要求 |
|
|
51
54
|
| --- | --- |
|
|
52
55
|
| Node.js | 20.18.1 或更高版本 |
|
|
53
|
-
| Java |
|
|
56
|
+
| Java | 无需预装;缺少时自动下载(游戏所需版本,以及 HeadlessMC 所需的 Java 25) |
|
|
54
57
|
| 磁盘 | 每个游戏版本约 0.5–1 GB,资源文件在各版本间共享 |
|
|
55
58
|
| Linux 截图 | `xvfb`、`libgl1-mesa-dri`;Minecraft 26.x 另需 `libegl1`、`libegl-mesa0` |
|
|
56
59
|
|
|
@@ -91,6 +94,18 @@ calcite launch play.example.com -V 1.21.11 -n Bot1
|
|
|
91
94
|
| `:shot [文件]` | 截图并保存为 PNG |
|
|
92
95
|
| `:render on\|off` | 开启或关闭持续渲染 |
|
|
93
96
|
| `:respawn` | 死亡后重生 |
|
|
97
|
+
| `:look <yaw> <pitch>` / `:lookat <x> <y> <z>` | 设置视角 / 看向坐标 |
|
|
98
|
+
| `:goto <x> <z>` | 直线走到指定坐标,遇到台阶自动跳跃 |
|
|
99
|
+
| `:move <按键,...> [tick]` | 按住按键若干 tick(默认 20),按键为 `forward`、`back`、`left`、`right`、`jump`、`sneak`、`sprint`、`attack`、`use` |
|
|
100
|
+
| `:stop` | 停止当前移动、挖掘等持续操作 |
|
|
101
|
+
| `:attack [实体ID]` | 攻击指定实体;省略时攻击准星所指 |
|
|
102
|
+
| `:use [实体ID \| x y z] [tick]` | 右键实体或方块;省略目标时使用手中物品,可指定按住时长 |
|
|
103
|
+
| `:dig <x> <y> <z>` | 挖掘方块直至破坏 |
|
|
104
|
+
| `:block <x> <y> <z>` / `:target` | 查看方块 / 查看准星目标 |
|
|
105
|
+
| `:inv` / `:slot <0-8>` | 查看背包 / 切换快捷栏 |
|
|
106
|
+
| `:container` / `:close` | 查看 / 关闭当前打开的容器 |
|
|
107
|
+
| `:click <槽位> [按键] [模式]` | 点击容器槽位,模式见下文 |
|
|
108
|
+
| `:drop [all]` | 丢弃手中物品(`all` 丢弃整组) |
|
|
94
109
|
| `:quit` | 退出并关闭客户端 |
|
|
95
110
|
|
|
96
111
|
### 命令一览
|
|
@@ -98,7 +113,7 @@ calcite launch play.example.com -V 1.21.11 -n Bot1
|
|
|
98
113
|
| 命令 | 说明 |
|
|
99
114
|
| --- | --- |
|
|
100
115
|
| `calcite launch [server]` | 启动客户端并在终端中交互 |
|
|
101
|
-
| `calcite install [version]` | 预下载指定版本(客户端、库、资源、Java
|
|
116
|
+
| `calcite install [version]` | 预下载指定版本(客户端、库、资源、Java),不启动游戏;`-l, --loader` 同时安装模组加载器 |
|
|
102
117
|
| `calcite versions` | 列出可用版本(`-t release\|snapshot\|old_beta\|old_alpha\|all`,`-l <数量>`) |
|
|
103
118
|
| `calcite login` | 微软账号登录(设备码) |
|
|
104
119
|
| `calcite accounts` | 列出已保存的微软账号 |
|
|
@@ -115,6 +130,8 @@ calcite launch play.example.com -V 1.21.11 -n Bot1
|
|
|
115
130
|
| `-u, --username <name>` | 实例名 | 离线用户名 |
|
|
116
131
|
| `-m, --microsoft [account]` | — | 使用已保存的微软账号(省略名称时使用主账号) |
|
|
117
132
|
| `-r, --render <mode>` | `on-demand` | 渲染模式:`on-demand`、`always`、`off` |
|
|
133
|
+
| `-l, --loader <loader>` | — | 模组加载器:`fabric`、`forge`、`neoforge`,可加 `@<版本>`,见[模组](#模组) |
|
|
134
|
+
| `--mod <spec>` | — | 加载模组,可重复;需同时指定加载器 |
|
|
118
135
|
| `--java <path>` | 自动选择 | 指定游戏使用的 Java |
|
|
119
136
|
| `--no-java-download` | — | 禁止自动下载 Java |
|
|
120
137
|
| `--memory <size>` | `2G` | 最大堆内存 |
|
|
@@ -154,7 +171,7 @@ claude mcp add calcite -- npx -y @bkm016/calcite mcp
|
|
|
154
171
|
|
|
155
172
|
| 工具 | 说明 |
|
|
156
173
|
| --- | --- |
|
|
157
|
-
| `launch_client` |
|
|
174
|
+
| `launch_client` | 启动客户端,可指定服务器、版本、离线用户名或微软账号、渲染模式、模组加载器与模组 |
|
|
158
175
|
| `stop_client` | 停止客户端 |
|
|
159
176
|
| `list_clients` | 列出当前管理的客户端 |
|
|
160
177
|
| `get_state` | 获取生命周期阶段与游戏状态(界面、坐标、生命值、维度、帧率、断开原因) |
|
|
@@ -167,7 +184,22 @@ claude mcp add calcite -- npx -y @bkm016/calcite mcp
|
|
|
167
184
|
| `get_logs` | 获取游戏日志与 Calcite 日志,用于排查崩溃 |
|
|
168
185
|
| `set_render` | 开启或关闭持续渲染 |
|
|
169
186
|
| `respawn` | 死亡后重生 |
|
|
170
|
-
| `
|
|
187
|
+
| `look` | 设置视角,或看向指定坐标 |
|
|
188
|
+
| `walk_to` | 直线走到指定坐标,遇障碍自动跳跃,返回是否到达 |
|
|
189
|
+
| `move` | 按住移动、跳跃、潜行、疾跑等按键若干 tick |
|
|
190
|
+
| `stop_actions` | 停止所有持续操作并松开按键 |
|
|
191
|
+
| `attack` | 攻击实体(按 ID 或准星目标) |
|
|
192
|
+
| `use` | 右键:使用手中物品、与方块交互(开箱、放置)、与实体交互 |
|
|
193
|
+
| `dig` | 挖掘方块直至破坏 |
|
|
194
|
+
| `get_block` | 查询方块 ID 与方块状态 |
|
|
195
|
+
| `get_target` | 查询准星所指的方块或实体 |
|
|
196
|
+
| `get_inventory` | 查询背包、快捷栏与手持物品 |
|
|
197
|
+
| `select_slot` | 切换快捷栏槽位 |
|
|
198
|
+
| `get_container` | 查询当前打开的容器(类型、标题、槽位物品) |
|
|
199
|
+
| `click_slot` | 点击容器槽位,支持拾取、快速移动、数字键交换、丢弃等模式 |
|
|
200
|
+
| `close_container` | 关闭当前容器 |
|
|
201
|
+
| `drop_item` | 丢弃手中物品 |
|
|
202
|
+
| `install_version` | 预下载指定版本,可同时安装模组加载器 |
|
|
171
203
|
| `list_versions` | 列出可用版本 |
|
|
172
204
|
| `account_login_start` | 开始微软账号登录,返回验证链接 |
|
|
173
205
|
| `account_login_status` | 查询登录进度 |
|
|
@@ -210,6 +242,8 @@ await bot.stop();
|
|
|
210
242
|
| `server` | `host[:port]`;省略时停留在标题界面 |
|
|
211
243
|
| `account` | `{ type: 'offline', username }` 或 `{ type: 'microsoft', name? }` |
|
|
212
244
|
| `render` | `on-demand`(默认)、`always`、`off` |
|
|
245
|
+
| `loader` | 模组加载器:`fabric`、`forge`、`neoforge`,可加 `@<版本>` |
|
|
246
|
+
| `mods` | 模组列表:本地 jar 或目录、http(s) URL、`modrinth:<项目>[@<版本>]` |
|
|
213
247
|
| `memory` | 最大堆内存,默认 `2G` |
|
|
214
248
|
| `javaPath` / `allowJavaDownload` | 指定 Java 路径 / 是否允许自动下载 |
|
|
215
249
|
| `jvmArgs` / `gameArgs` | 额外的 JVM 参数 / 游戏参数 |
|
|
@@ -231,9 +265,37 @@ await bot.stop();
|
|
|
231
265
|
| `waitFor(cond, timeoutMs)` | 等待聊天、实体或阶段条件 |
|
|
232
266
|
| `setRender(enabled)` / `respawn()` | 切换持续渲染 / 重生 |
|
|
233
267
|
| `chatSince(seq)` / `logsSince(opts)` | 读取聊天与日志缓冲 |
|
|
268
|
+
| `look({ yaw, pitch } \| { x, y, z })` | 设置视角或看向坐标 |
|
|
269
|
+
| `walkTo(x, z, { range, sprint, timeoutMs })` | 走到坐标,返回 `{ arrived, reason?, distance, x, y, z }` |
|
|
270
|
+
| `move(controls, { ticks })` / `stopActions()` | 按住按键若干 tick / 停止所有持续操作 |
|
|
271
|
+
| `attack(entityId?)` | 攻击实体,省略时攻击准星目标 |
|
|
272
|
+
| `use({ entityId?, block?, holdTicks? })` | 右键实体、方块或使用手中物品 |
|
|
273
|
+
| `dig(block, { timeoutMs })` | 挖掘方块,返回 `{ broken, block, ticks?, reason? }` |
|
|
274
|
+
| `block(pos)` / `target()` | 查询方块 / 准星目标 |
|
|
275
|
+
| `inventory()` / `selectSlot(n)` | 查询背包 / 切换快捷栏 |
|
|
276
|
+
| `container({ waitMs })` / `closeContainer()` | 查询 / 关闭当前容器 |
|
|
277
|
+
| `click(slot, { button, mode })` | 点击容器槽位 |
|
|
278
|
+
| `drop({ all })` | 丢弃手中物品 |
|
|
234
279
|
|
|
235
280
|
事件:`phase`、`state`、`chat`、`log`、`exit`。
|
|
236
281
|
|
|
282
|
+
### 玩家操作示例
|
|
283
|
+
|
|
284
|
+
```js
|
|
285
|
+
await bot.walkTo(100.5, 200.5); // 走到 (100.5, 200.5)
|
|
286
|
+
await bot.dig({ x: 101, y: 64, z: 200 }); // 挖掉一个方块
|
|
287
|
+
await bot.use({ block: { x: 100, y: 64, z: 202 } }); // 右键打开箱子
|
|
288
|
+
const chest = await bot.container({ waitMs: 3000 }); // 等待容器界面打开
|
|
289
|
+
for (const item of chest.items.filter((i) => i.slot < chest.containerSlots)) {
|
|
290
|
+
await bot.click(item.slot, { mode: 'quick_move' }); // Shift+点击 取出物品
|
|
291
|
+
}
|
|
292
|
+
await bot.closeContainer();
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
容器槽位编号与原版一致:容器自身的槽位在前(`0` 到 `containerSlots - 1`),玩家背包在后;`item.inventorySlot` 给出对应的背包槽位。`click` 的 `mode` 可取 `pickup`(默认,`button` 0 为左键、1 为右键)、`quick_move`(Shift+点击)、`swap`(数字键,`button` 为快捷栏序号 0–8)、`clone`、`throw`、`quick_craft`、`pickup_all`;槽位 `-999` 表示点击界面外部。未打开容器时,`click` 作用于玩家自身的背包界面。
|
|
296
|
+
|
|
297
|
+
操作有距离限制(6 格):目标过远时返回 `out_of_reach` 错误,需先用 `walkTo` 靠近。
|
|
298
|
+
|
|
237
299
|
此外还导出 `ClientManager`(多客户端管理)、`installVersion`、`startLogin`、`listAccounts`、`removeAccount` 等函数,类型定义随包发布。
|
|
238
300
|
|
|
239
301
|
## 平台与账号
|
|
@@ -243,10 +305,12 @@ await bot.stop();
|
|
|
243
305
|
| Linux | 全部功能(在 Xvfb 中渲染) | 全部功能 |
|
|
244
306
|
| Windows / macOS | 无渲染运行,不支持截图,其余功能正常 | 全部功能 |
|
|
245
307
|
|
|
246
|
-
HeadlessMC
|
|
308
|
+
HeadlessMC 仅在检测到 Xvfb 时允许离线账号渲染,否则强制以无渲染方式运行。这是上游策略,Calcite 遵循该策略。如需在 Windows 或 macOS 上截图,请使用正版账号。
|
|
247
309
|
|
|
248
310
|
离线账号只能进入 `online-mode=false` 的服务器。
|
|
249
311
|
|
|
312
|
+
从 0.1.x 升级:Calcite 现使用 HeadlessMC 3,其凭据格式与 HeadlessMC 2 不兼容,已保存的微软账号需要重新执行一次 `calcite login`。
|
|
313
|
+
|
|
250
314
|
## 渲染模式
|
|
251
315
|
|
|
252
316
|
| 模式 | 说明 |
|
|
@@ -255,11 +319,42 @@ HeadlessMC 仅允许离线账号在 Linux 虚拟显示器中渲染。这是上
|
|
|
255
319
|
| `always` | 持续渲染,适合在本地桌面观察 |
|
|
256
320
|
| `off` | 以无渲染器方式运行(替换 LWJGL),资源占用最低,不支持截图 |
|
|
257
321
|
|
|
322
|
+
## 模组
|
|
323
|
+
|
|
324
|
+
```bash
|
|
325
|
+
# Fabric + Fabric API(从 Modrinth 下载,自动补全前置)
|
|
326
|
+
calcite launch localhost -V 1.21.11 -l fabric --mod modrinth:fabric-api --mod ./mods/my-mod.jar
|
|
327
|
+
|
|
328
|
+
# 指定加载器版本
|
|
329
|
+
calcite launch localhost -V 1.20.1 -l forge@47.4.26
|
|
330
|
+
calcite install 1.21.11 -l neoforge
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
```js
|
|
334
|
+
new Client({ version: '1.21.11', loader: 'fabric', mods: ['modrinth:fabric-api', './my-mod.jar'] });
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
- 加载器由 HeadlessMC 安装到共享的 `minecraft/versions/`,省略版本时使用最新版本(已安装过则复用本地最新版)。
|
|
338
|
+
- 模组来源:本地 jar、包含 jar 的目录、http(s) URL,或 `modrinth:<项目>[@<版本号>]`。Modrinth 模组按游戏版本与加载器挑选最新正式版,并自动下载必需的前置模组;下载文件按哈希校验并缓存在 `mods/`。
|
|
339
|
+
- 模组复制到实例的 `mods/` 目录。Calcite 只管理自己放入的文件(记录在 `mods/.calcite-mods.json`),手动放入的模组不受影响。
|
|
340
|
+
- 模组加载失败时,客户端会停在错误界面;Calcite 检测到后立即结束进程并返回 `mod_loading_failed`,错误信息附带相关日志。
|
|
341
|
+
|
|
342
|
+
| 加载器 | 支持的版本 | 探针 |
|
|
343
|
+
| --- | --- | --- |
|
|
344
|
+
| Fabric | Fabric 支持的所有版本 | 全部功能(自动将 Mojang 映射转换为 intermediary 名称) |
|
|
345
|
+
| NeoForge | 1.20.2 及以上 | 全部功能 |
|
|
346
|
+
| Forge | 1.17 及以上 | 全部功能(1.20.4 及以前自动转换为 SRG 名称) |
|
|
347
|
+
| Forge | 1.16.5 及以前 | 可以启动,探针功能不可用 |
|
|
348
|
+
|
|
349
|
+
Forge 与 NeoForge 的安装器要求与游戏版本完全一致的 Java 主版本(例如 1.20.1 需要 Java 17),缺少时自动下载。Forge 与 NeoForge 不支持在 render `off` 下运行原本需要 Java 8 的版本。
|
|
350
|
+
|
|
351
|
+
已验证:Fabric 1.21.11 / 26.3(含 Fabric API)、NeoForge 1.20.4 / 1.21.11、Forge 1.20.1 / 1.21.1。
|
|
352
|
+
|
|
258
353
|
## 版本兼容性
|
|
259
354
|
|
|
260
355
|
| 版本范围 | 支持情况 |
|
|
261
356
|
| --- | --- |
|
|
262
|
-
| 1.14.4 及以上 |
|
|
357
|
+
| 1.14.4 及以上 | 全部功能(状态、实体、聊天、指令、截图、玩家操作) |
|
|
263
358
|
| 1.14.4 以前 | 可以启动并进入服务器;Mojang 未发布这些版本的映射表,探针功能不可用 |
|
|
264
359
|
|
|
265
360
|
已验证的版本:1.16.5、1.20.4、1.21.11、26.3。
|
|
@@ -272,14 +367,17 @@ HeadlessMC 仅允许离线账号在 Linux 虚拟显示器中渲染。这是上
|
|
|
272
367
|
| --- | --- |
|
|
273
368
|
| `minecraft/` | 各版本共享的游戏文件、库与资源 |
|
|
274
369
|
| `instances/<name>/` | 各实例独立的游戏目录(`options.txt`、日志、截图) |
|
|
275
|
-
| `hmc-home/
|
|
370
|
+
| `hmc-home/.auth/default/` | 已保存的微软登录凭据(权限 600,请妥善保管) |
|
|
371
|
+
| `instances/<name>/.headlessmc/` | 该实例的 HeadlessMC 配置、账号副本与缓存 |
|
|
276
372
|
| `java/` | 自动下载的 Java 运行时 |
|
|
373
|
+
| `mods/` | 从 URL 与 Modrinth 下载的模组缓存 |
|
|
374
|
+
| `mappings/` | 映射表及为模组加载器转换后的名称表 |
|
|
277
375
|
|
|
278
376
|
| 环境变量 | 说明 |
|
|
279
377
|
| --- | --- |
|
|
280
378
|
| `CALCITE_HOME` | 数据目录 |
|
|
281
379
|
| `CALCITE_LOG_LEVEL` | 日志级别:`debug`、`info`、`warn`、`error`、`silent` |
|
|
282
|
-
| `HTTPS_PROXY` / `HTTP_PROXY` / `NO_PROXY` |
|
|
380
|
+
| `HTTPS_PROXY` / `HTTP_PROXY` / `NO_PROXY` | HTTP 代理。Calcite 自身的下载使用该代理,并将其转换为 Java 系统属性传给 HeadlessMC 与游戏进程(Java 不支持代理认证;游戏与服务器之间的连接不经过代理) |
|
|
283
381
|
| `CALCITE_JAVA_<主版本>` | 指定某个 Java 主版本的路径,例如 `CALCITE_JAVA_8` |
|
|
284
382
|
| `CALCITE_HMC_JAR` / `CALCITE_HMC_URL` | 使用自定义的 HeadlessMC |
|
|
285
383
|
| `CALCITE_PROBE_DIR` | 探针目录,路径中不能包含空格 |
|
|
@@ -298,14 +396,18 @@ HeadlessMC 仅允许离线账号在 Linux 虚拟显示器中渲染。这是上
|
|
|
298
396
|
| `not_logged_in` / `unknown_account` | 未登录微软账号或账号名不存在。请先执行 `calcite login` |
|
|
299
397
|
| `instance_busy` | 同名实例已在其他进程中运行 |
|
|
300
398
|
| `unsupported_version` | 版本不存在或不受支持 |
|
|
399
|
+
| `bad_loader` / `unsupported_loader` | 加载器名称或版本格式错误 / 该版本组合无法运行 |
|
|
400
|
+
| `install_failed` | HeadlessMC 未能安装加载器(该游戏版本可能没有对应构建) |
|
|
401
|
+
| `bad_mod` / `mod_not_found` | 模组参数错误 / 找不到模组文件或 Modrinth 上没有适配的版本 |
|
|
402
|
+
| `mod_loading_failed` | 模组加载失败(缺少前置、版本不兼容等),错误信息附带日志 |
|
|
301
403
|
|
|
302
404
|
排查环境问题时,建议先运行 `calcite doctor`。
|
|
303
405
|
|
|
304
406
|
## 工作原理
|
|
305
407
|
|
|
306
408
|
1. Calcite 解析 Mojang 版本清单,下载客户端、库与资源文件,并逐一校验哈希。
|
|
307
|
-
2. 使用 [HeadlessMC](https://github.com/headlesshq/headlessmc)
|
|
308
|
-
3. 向游戏注入一个轻量 Java Agent(探针)。探针借助 Mojang
|
|
409
|
+
2. 使用 [HeadlessMC](https://github.com/headlesshq/headlessmc) 3 启动游戏。每个实例拥有独立的游戏目录、HeadlessMC 配置和启动参数,并发启动互不干扰。
|
|
410
|
+
3. 向游戏注入一个轻量 Java Agent(探针)。探针借助 Mojang 官方映射表(模组环境下转换为 intermediary 或 SRG 名称)定位游戏内部类,并通过本地 TCP 连接与 Calcite 交换 JSON 消息。
|
|
309
411
|
4. 在 Linux 无显示环境中,Calcite 启动共享的 Xvfb,并配置 Mesa 软件渲染。Minecraft 26.x 的渲染器改用 EGL。
|
|
310
412
|
|
|
311
413
|
## 许可
|
package/dist/accounts.d.ts
CHANGED
|
@@ -1,16 +1,35 @@
|
|
|
1
1
|
import type { CalcitePaths } from './paths.js';
|
|
2
|
-
/** HeadlessMC
|
|
2
|
+
/** HeadlessMC files location holding the Microsoft sessions created by `calcite login`. */
|
|
3
|
+
export declare function accountsHome(paths: CalcitePaths): string;
|
|
4
|
+
/** Microsoft sessions of `calcite login`; Calcite restricts the file to the current user. */
|
|
3
5
|
export declare function accountsFile(paths: CalcitePaths): string;
|
|
4
6
|
export declare function accountsLock(paths: CalcitePaths): string;
|
|
5
7
|
export interface AccountInfo {
|
|
6
8
|
name: string;
|
|
7
9
|
uuid?: string;
|
|
8
|
-
/** The account
|
|
10
|
+
/** The account used when a client does not name one. */
|
|
9
11
|
primary: boolean;
|
|
10
12
|
}
|
|
11
|
-
/** Stored Microsoft accounts (no secrets).
|
|
13
|
+
/** Stored Microsoft accounts (no secrets). */
|
|
12
14
|
export declare function listAccounts(paths: CalcitePaths): Promise<AccountInfo[]>;
|
|
13
15
|
export declare function removeAccount(paths: CalcitePaths, name: string): Promise<boolean>;
|
|
16
|
+
/** UUID the vanilla server assigns to an offline player (version 3, from "OfflinePlayer:<name>"), without dashes. */
|
|
17
|
+
export declare function offlineUuid(name: string): string;
|
|
18
|
+
export type LaunchAccount = {
|
|
19
|
+
type: 'offline';
|
|
20
|
+
username: string;
|
|
21
|
+
} | {
|
|
22
|
+
type: 'microsoft';
|
|
23
|
+
name?: string;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Prepares the private HeadlessMC location of one client so that HeadlessMC launches exactly this account.
|
|
27
|
+
* Microsoft sessions are copied from the `calcite login` store; {@link syncAccount} writes refreshed tokens back.
|
|
28
|
+
* Returns the account name.
|
|
29
|
+
*/
|
|
30
|
+
export declare function prepareAccount(paths: CalcitePaths, location: string, account: LaunchAccount): Promise<string>;
|
|
31
|
+
/** Copies a Microsoft session refreshed by a launch back into the `calcite login` store. */
|
|
32
|
+
export declare function syncAccount(paths: CalcitePaths, location: string, name: string): Promise<void>;
|
|
14
33
|
export interface LoginHandle {
|
|
15
34
|
/** Microsoft device login URL (contains the code); open it in a browser and approve. */
|
|
16
35
|
url: Promise<string>;
|
|
@@ -20,7 +39,7 @@ export interface LoginHandle {
|
|
|
20
39
|
}
|
|
21
40
|
/**
|
|
22
41
|
* Starts a Microsoft device-code login through HeadlessMC. The session (including the refresh token) is stored
|
|
23
|
-
* in
|
|
42
|
+
* in Calcite's HeadlessMC location and refreshed automatically on every launch.
|
|
24
43
|
*/
|
|
25
44
|
export declare function startLogin(paths: CalcitePaths, { timeoutMs }?: {
|
|
26
45
|
timeoutMs?: number | undefined;
|
package/dist/accounts.js
CHANGED
|
@@ -1,70 +1,151 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { chmod, mkdir, readFile, rm, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
import { ensureHmc, killTree, runHmc } from './hmc.js';
|
|
4
5
|
import { ensureLauncherJava } from './java.js';
|
|
5
6
|
import { withLock } from './lock.js';
|
|
6
|
-
/** HeadlessMC
|
|
7
|
+
/** HeadlessMC account providers. */
|
|
8
|
+
const MICROSOFT = 'default';
|
|
9
|
+
const OFFLINE = 'offline';
|
|
10
|
+
/** HeadlessMC files location holding the Microsoft sessions created by `calcite login`. */
|
|
11
|
+
export function accountsHome(paths) {
|
|
12
|
+
return paths.hmcHome;
|
|
13
|
+
}
|
|
14
|
+
/** HeadlessMC 3 stores the sessions (including refresh tokens) of one provider in this file. */
|
|
15
|
+
function storeFile(location, provider) {
|
|
16
|
+
return join(location, '.auth', provider, '.accounts.json');
|
|
17
|
+
}
|
|
18
|
+
function lastUsedFile(location) {
|
|
19
|
+
return join(location, '.auth', 'last', '.accounts.json');
|
|
20
|
+
}
|
|
21
|
+
/** Microsoft sessions of `calcite login`; Calcite restricts the file to the current user. */
|
|
7
22
|
export function accountsFile(paths) {
|
|
8
|
-
return
|
|
23
|
+
return storeFile(accountsHome(paths), MICROSOFT);
|
|
9
24
|
}
|
|
10
25
|
export function accountsLock(paths) {
|
|
11
26
|
return join(paths.hmcHome, 'accounts.lock');
|
|
12
27
|
}
|
|
13
|
-
function
|
|
14
|
-
|
|
15
|
-
|
|
28
|
+
async function readStore(file) {
|
|
29
|
+
try {
|
|
30
|
+
const data = JSON.parse(await readFile(file, 'utf8'));
|
|
31
|
+
return data.accounts && typeof data.accounts === 'object' && !Array.isArray(data.accounts) ? data.accounts : {};
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return {};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
async function writeStore(file, accounts) {
|
|
38
|
+
await mkdir(dirname(file), { recursive: true });
|
|
39
|
+
await writeFile(file, JSON.stringify({ accounts, version: 0 }, null, 2), { mode: 0o600 });
|
|
40
|
+
if (process.platform !== 'win32')
|
|
41
|
+
await chmod(file, 0o600).catch(() => undefined); // Windows: the profile ACL applies
|
|
42
|
+
}
|
|
43
|
+
function findKey(accounts, name) {
|
|
44
|
+
return Object.keys(accounts).find((k) => k.toLowerCase() === name.toLowerCase());
|
|
45
|
+
}
|
|
46
|
+
/** The Minecraft profile id inside a stored MinecraftAuth session (an object carrying both the name and the id). */
|
|
47
|
+
function findUuid(session, name) {
|
|
48
|
+
const stack = [session];
|
|
16
49
|
while (stack.length) {
|
|
17
50
|
const node = stack.pop();
|
|
18
51
|
if (!node || typeof node !== 'object')
|
|
19
52
|
continue;
|
|
20
53
|
const obj = node;
|
|
21
|
-
if (obj.
|
|
22
|
-
|
|
23
|
-
return { name: typeof p.name === 'string' ? p.name : undefined, uuid: typeof p.id === 'string' ? p.id : undefined };
|
|
24
|
-
}
|
|
54
|
+
if (typeof obj.name === 'string' && obj.name.toLowerCase() === name.toLowerCase() && typeof obj.id === 'string')
|
|
55
|
+
return obj.id;
|
|
25
56
|
for (const v of Object.values(obj))
|
|
26
57
|
if (v && typeof v === 'object')
|
|
27
58
|
stack.push(v);
|
|
28
59
|
}
|
|
29
|
-
return
|
|
60
|
+
return undefined;
|
|
30
61
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
62
|
+
/** Name of the most recently used Microsoft account of a HeadlessMC location. */
|
|
63
|
+
async function lastUsed(location) {
|
|
64
|
+
const latest = (await readStore(lastUsedFile(location))).latest;
|
|
65
|
+
if (!Array.isArray(latest))
|
|
66
|
+
return undefined;
|
|
67
|
+
const entry = latest.find((e) => e && typeof e === 'object' && e.provider === MICROSOFT);
|
|
68
|
+
return typeof entry?.name === 'string' ? entry.name : undefined;
|
|
39
69
|
}
|
|
40
|
-
/** Stored Microsoft accounts (no secrets).
|
|
70
|
+
/** Stored Microsoft accounts (no secrets). */
|
|
41
71
|
export async function listAccounts(paths) {
|
|
42
|
-
|
|
72
|
+
const accounts = await readStore(accountsFile(paths));
|
|
73
|
+
const names = Object.keys(accounts);
|
|
74
|
+
const last = await lastUsed(accountsHome(paths));
|
|
75
|
+
const primary = (last && findKey(accounts, last)) ?? names[0];
|
|
76
|
+
return names.map((name) => ({ name, uuid: findUuid(accounts[name], name), primary: name === primary }));
|
|
43
77
|
}
|
|
44
78
|
export async function removeAccount(paths, name) {
|
|
45
79
|
return withLock(accountsLock(paths), async () => {
|
|
46
|
-
const accounts = await
|
|
47
|
-
const
|
|
48
|
-
if (
|
|
80
|
+
const accounts = await readStore(accountsFile(paths));
|
|
81
|
+
const key = findKey(accounts, name);
|
|
82
|
+
if (!key)
|
|
49
83
|
return false;
|
|
50
|
-
|
|
51
|
-
await
|
|
84
|
+
delete accounts[key];
|
|
85
|
+
await writeStore(accountsFile(paths), accounts);
|
|
52
86
|
return true;
|
|
53
87
|
});
|
|
54
88
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
89
|
+
/** UUID the vanilla server assigns to an offline player (version 3, from "OfflinePlayer:<name>"), without dashes. */
|
|
90
|
+
export function offlineUuid(name) {
|
|
91
|
+
const hash = createHash('md5').update(`OfflinePlayer:${name}`, 'utf8').digest();
|
|
92
|
+
hash[6] = (hash[6] & 0x0f) | 0x30;
|
|
93
|
+
hash[8] = (hash[8] & 0x3f) | 0x80;
|
|
94
|
+
return hash.toString('hex');
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Prepares the private HeadlessMC location of one client so that HeadlessMC launches exactly this account.
|
|
98
|
+
* Microsoft sessions are copied from the `calcite login` store; {@link syncAccount} writes refreshed tokens back.
|
|
99
|
+
* Returns the account name.
|
|
100
|
+
*/
|
|
101
|
+
export async function prepareAccount(paths, location, account) {
|
|
102
|
+
if (account.type === 'offline') {
|
|
103
|
+
const name = account.username;
|
|
104
|
+
await rm(storeFile(location, MICROSOFT), { force: true });
|
|
105
|
+
await writeStore(storeFile(location, OFFLINE), {
|
|
106
|
+
[name]: { provider: OFFLINE, name, uuid: offlineUuid(name), token: '', type: 'msa', xuid: '' },
|
|
107
|
+
});
|
|
108
|
+
await writeStore(lastUsedFile(location), { latest: [{ provider: OFFLINE, name }] });
|
|
109
|
+
return name;
|
|
110
|
+
}
|
|
111
|
+
return withLock(accountsLock(paths), async () => {
|
|
112
|
+
const accounts = await listAccounts(paths);
|
|
113
|
+
if (!accounts.length)
|
|
114
|
+
throw Object.assign(new Error('No Microsoft account is stored; run `calcite login` first'), { code: 'not_logged_in' });
|
|
115
|
+
const wanted = account.name;
|
|
116
|
+
const match = wanted ? accounts.find((a) => a.name.toLowerCase() === wanted.toLowerCase()) : accounts.find((a) => a.primary);
|
|
117
|
+
if (!match) {
|
|
118
|
+
throw Object.assign(new Error(`No stored Microsoft account named "${wanted}" (have: ${accounts.map((a) => a.name).join(', ')})`), { code: 'unknown_account' });
|
|
119
|
+
}
|
|
120
|
+
const session = (await readStore(accountsFile(paths)))[match.name];
|
|
121
|
+
await rm(storeFile(location, OFFLINE), { force: true });
|
|
122
|
+
await writeStore(storeFile(location, MICROSOFT), { [match.name]: session });
|
|
123
|
+
await writeStore(lastUsedFile(location), { latest: [{ provider: MICROSOFT, name: match.name }] });
|
|
124
|
+
return match.name;
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
/** Copies a Microsoft session refreshed by a launch back into the `calcite login` store. */
|
|
128
|
+
export async function syncAccount(paths, location, name) {
|
|
129
|
+
const local = await readStore(storeFile(location, MICROSOFT));
|
|
130
|
+
const key = findKey(local, name);
|
|
131
|
+
if (!key)
|
|
132
|
+
return;
|
|
133
|
+
await withLock(accountsLock(paths), async () => {
|
|
134
|
+
const accounts = await readStore(accountsFile(paths));
|
|
135
|
+
const central = findKey(accounts, name);
|
|
136
|
+
if (!central || JSON.stringify(accounts[central]) === JSON.stringify(local[key]))
|
|
137
|
+
return; // removed meanwhile, or unchanged
|
|
138
|
+
accounts[central] = local[key];
|
|
139
|
+
await writeStore(accountsFile(paths), accounts);
|
|
140
|
+
});
|
|
59
141
|
}
|
|
60
142
|
/**
|
|
61
143
|
* Starts a Microsoft device-code login through HeadlessMC. The session (including the refresh token) is stored
|
|
62
|
-
* in
|
|
144
|
+
* in Calcite's HeadlessMC location and refreshed automatically on every launch.
|
|
63
145
|
*/
|
|
64
146
|
export async function startLogin(paths, { timeoutMs = 15 * 60_000 } = {}) {
|
|
65
147
|
const java = await ensureLauncherJava(paths);
|
|
66
148
|
const hmcJar = await ensureHmc(paths);
|
|
67
|
-
await ensureHmcHome(paths);
|
|
68
149
|
let resolveUrl;
|
|
69
150
|
let rejectUrl;
|
|
70
151
|
const url = new Promise((res, rej) => {
|
|
@@ -76,17 +157,16 @@ export async function startLogin(paths, { timeoutMs = 15 * 60_000 } = {}) {
|
|
|
76
157
|
const run = runHmc({
|
|
77
158
|
javaPath: java.path,
|
|
78
159
|
hmcJar,
|
|
79
|
-
paths,
|
|
80
|
-
props: { 'hmc.store.accounts': 'true' },
|
|
160
|
+
location: accountsHome(paths),
|
|
81
161
|
command: ['login'],
|
|
82
162
|
onLine: (line) => {
|
|
83
|
-
const go = /
|
|
163
|
+
const go = /To login visit (https?:\/\/\S+)/.exec(line);
|
|
84
164
|
if (go)
|
|
85
165
|
resolveUrl(go[1]);
|
|
86
|
-
const ok = /Logged
|
|
166
|
+
const ok = /Logged in to account (.+?) successfully/.exec(line);
|
|
87
167
|
if (ok)
|
|
88
168
|
account = ok[1];
|
|
89
|
-
if (/Failed to login|You can't play|
|
|
169
|
+
if (/AuthException|Failed to login|You can't play|Exception:/.test(line) && !failure)
|
|
90
170
|
failure = line.trim();
|
|
91
171
|
},
|
|
92
172
|
});
|
|
@@ -98,7 +178,7 @@ export async function startLogin(paths, { timeoutMs = 15 * 60_000 } = {}) {
|
|
|
98
178
|
rejectUrl(err);
|
|
99
179
|
throw err;
|
|
100
180
|
}
|
|
101
|
-
await
|
|
181
|
+
await chmod(accountsFile(paths), 0o600).catch(() => undefined);
|
|
102
182
|
return account;
|
|
103
183
|
});
|
|
104
184
|
done.catch(() => undefined);
|
package/dist/accounts.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"accounts.js","sourceRoot":"","sources":["../src/accounts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"accounts.js","sourceRoot":"","sources":["../src/accounts.ts"],"names":[],"mappings":"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"}
|