@bkm016/calcite 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +314 -2
- package/THIRD_PARTY_NOTICES.md +44 -0
- package/dist/accounts.d.ts +27 -0
- package/dist/accounts.js +114 -0
- package/dist/accounts.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +242 -0
- package/dist/cli.js.map +1 -0
- package/dist/client.d.ts +251 -0
- package/dist/client.js +671 -0
- package/dist/client.js.map +1 -0
- package/dist/display.d.ts +23 -0
- package/dist/display.js +135 -0
- package/dist/display.js.map +1 -0
- package/dist/hmc.d.ts +33 -0
- package/dist/hmc.js +130 -0
- package/dist/hmc.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/java.d.ts +31 -0
- package/dist/java.js +218 -0
- package/dist/java.js.map +1 -0
- package/dist/lock.d.ts +13 -0
- package/dist/lock.js +79 -0
- package/dist/lock.js.map +1 -0
- package/dist/log.d.ts +13 -0
- package/dist/log.js +20 -0
- package/dist/log.js.map +1 -0
- package/dist/manager.d.ts +15 -0
- package/dist/manager.js +65 -0
- package/dist/manager.js.map +1 -0
- package/dist/mcp.d.ts +13 -0
- package/dist/mcp.js +252 -0
- package/dist/mcp.js.map +1 -0
- package/dist/mojang.d.ts +70 -0
- package/dist/mojang.js +109 -0
- package/dist/mojang.js.map +1 -0
- package/dist/net.d.ts +21 -0
- package/dist/net.js +246 -0
- package/dist/net.js.map +1 -0
- package/dist/options.d.ts +14 -0
- package/dist/options.js +50 -0
- package/dist/options.js.map +1 -0
- package/dist/paths.d.ts +27 -0
- package/dist/paths.js +48 -0
- package/dist/paths.js.map +1 -0
- package/dist/probe-server.d.ts +28 -0
- package/dist/probe-server.js +132 -0
- package/dist/probe-server.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.js +11 -0
- package/dist/version.js.map +1 -0
- package/package.json +57 -4
- package/vendor/calcite-probe.jar +0 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 黑 <b@taboo.sh>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,315 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Calcite 方解石
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://github.com/bkm016/Calcite/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/@bkm016/calcite)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
Calcite 用于以编程方式驱动**真实的 Minecraft Java 版客户端**。它负责下载与启动游戏、加入服务器,并提供读取客户端状态与实体、发送聊天和指令、截图等能力。Calcite 以三种形式提供:
|
|
8
|
+
|
|
9
|
+
- **命令行工具**(`calcite`)
|
|
10
|
+
- **MCP 服务器**:供 Claude、Cursor 等 AI Agent 直接调用
|
|
11
|
+
- **Node.js 库**
|
|
12
|
+
|
|
13
|
+
适用场景包括服务端插件与模组的端到端测试、AI Agent 在游戏内的感知与操作,以及服务器的自动化巡检。
|
|
14
|
+
|
|
15
|
+
<p align="center">
|
|
16
|
+
<img src="docs/images/landscape.jpg" alt="Minecraft 26.3 风景截图" width="49%">
|
|
17
|
+
<img src="docs/images/gameplay.jpg" alt="Agent 在游戏中发送聊天与指令" width="49%">
|
|
18
|
+
</p>
|
|
19
|
+
<p align="center"><sub>两张图均由 Calcite 在无显卡的 Linux 云服务器上截取(Minecraft 26.3,Xvfb + Mesa 软件渲染)。右图为 Agent 发送聊天与指令后的画面。</sub></p>
|
|
20
|
+
|
|
21
|
+
## 目录
|
|
22
|
+
|
|
23
|
+
- [特性](#特性)
|
|
24
|
+
- [环境要求](#环境要求)
|
|
25
|
+
- [安装](#安装)
|
|
26
|
+
- [命令行](#命令行)
|
|
27
|
+
- [MCP 服务器](#mcp-服务器)
|
|
28
|
+
- [Node.js API](#nodejs-api)
|
|
29
|
+
- [平台与账号](#平台与账号)
|
|
30
|
+
- [渲染模式](#渲染模式)
|
|
31
|
+
- [版本兼容性](#版本兼容性)
|
|
32
|
+
- [数据目录与环境变量](#数据目录与环境变量)
|
|
33
|
+
- [故障排查](#故障排查)
|
|
34
|
+
- [工作原理](#工作原理)
|
|
35
|
+
- [许可](#许可)
|
|
36
|
+
|
|
37
|
+
## 特性
|
|
38
|
+
|
|
39
|
+
- **支持所有版本**:可启动 Mojang 发布的任意版本,包括正式版与快照;1.14.4 及以上版本支持全部探针功能。
|
|
40
|
+
- **跨平台**:Linux、Windows、macOS。
|
|
41
|
+
- **账号**:支持离线账号,也支持微软正版账号。正版账号使用设备码登录,凭据持久保存并自动刷新。
|
|
42
|
+
- **无显卡环境截图**:在 Linux 服务器上通过 Xvfb 与 Mesa 软件渲染完成截图。
|
|
43
|
+
- **按需渲染**:默认不渲染画面,截图时临时渲染。单次截图约 0.5 秒,进服后首次截图需等待区块编译,约 2–4 秒。
|
|
44
|
+
- **Java 自动管理**:按游戏版本自动选择 Java;本机缺少时从 Eclipse Adoptium 下载 Temurin,并校验 SHA-256。
|
|
45
|
+
- **自动重连**:掉线或崩溃后按指数退避自动重连。
|
|
46
|
+
- **多客户端**:一个进程可同时管理多个相互隔离的客户端实例。
|
|
47
|
+
|
|
48
|
+
## 环境要求
|
|
49
|
+
|
|
50
|
+
| 项目 | 要求 |
|
|
51
|
+
| --- | --- |
|
|
52
|
+
| Node.js | 20.18.1 或更高版本 |
|
|
53
|
+
| Java | 无需预装;缺少时自动下载 |
|
|
54
|
+
| 磁盘 | 每个游戏版本约 0.5–1 GB,资源文件在各版本间共享 |
|
|
55
|
+
| Linux 截图 | `xvfb`、`libgl1-mesa-dri`;Minecraft 26.x 另需 `libegl1`、`libegl-mesa0` |
|
|
56
|
+
|
|
57
|
+
Debian / Ubuntu 安装截图依赖:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
sudo apt install xvfb libgl1-mesa-dri libegl1 libegl-mesa0
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## 安装
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npm install -g @bkm016/calcite
|
|
67
|
+
calcite doctor
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`calcite doctor` 用于检查 Node.js、Java、显示环境、EGL、已保存账号以及 Mojang 服务的连通性。
|
|
71
|
+
|
|
72
|
+
## 命令行
|
|
73
|
+
|
|
74
|
+
### 快速开始
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
# 以离线账号 Bot1 进入服务器
|
|
78
|
+
calcite launch play.example.com -V 1.21.11 -n Bot1
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
客户端进服后,终端进入交互模式:
|
|
82
|
+
|
|
83
|
+
- 直接输入文本:发送聊天
|
|
84
|
+
- 以 `/` 开头:执行指令
|
|
85
|
+
- 以 `:` 开头:控制命令,见下表
|
|
86
|
+
|
|
87
|
+
| 交互命令 | 说明 |
|
|
88
|
+
| --- | --- |
|
|
89
|
+
| `:state` | 输出当前游戏状态 |
|
|
90
|
+
| `:ents [半径]` | 列出附近实体,默认半径 32 |
|
|
91
|
+
| `:shot [文件]` | 截图并保存为 PNG |
|
|
92
|
+
| `:render on\|off` | 开启或关闭持续渲染 |
|
|
93
|
+
| `:respawn` | 死亡后重生 |
|
|
94
|
+
| `:quit` | 退出并关闭客户端 |
|
|
95
|
+
|
|
96
|
+
### 命令一览
|
|
97
|
+
|
|
98
|
+
| 命令 | 说明 |
|
|
99
|
+
| --- | --- |
|
|
100
|
+
| `calcite launch [server]` | 启动客户端并在终端中交互 |
|
|
101
|
+
| `calcite install [version]` | 预下载指定版本(客户端、库、资源、Java),不启动游戏 |
|
|
102
|
+
| `calcite versions` | 列出可用版本(`-t release\|snapshot\|old_beta\|old_alpha\|all`,`-l <数量>`) |
|
|
103
|
+
| `calcite login` | 微软账号登录(设备码) |
|
|
104
|
+
| `calcite accounts` | 列出已保存的微软账号 |
|
|
105
|
+
| `calcite logout <name>` | 删除已保存的微软账号 |
|
|
106
|
+
| `calcite doctor` | 检查运行环境 |
|
|
107
|
+
| `calcite mcp` | 以 stdio 方式运行 MCP 服务器 |
|
|
108
|
+
|
|
109
|
+
### `launch` 参数
|
|
110
|
+
|
|
111
|
+
| 参数 | 默认值 | 说明 |
|
|
112
|
+
| --- | --- | --- |
|
|
113
|
+
| `-n, --name <name>` | `calcite` | 实例名,同时作为游戏目录名 |
|
|
114
|
+
| `-V, --mc-version <version>` | `release` | 版本号,也可使用 `release` 或 `snapshot` |
|
|
115
|
+
| `-u, --username <name>` | 实例名 | 离线用户名 |
|
|
116
|
+
| `-m, --microsoft [account]` | — | 使用已保存的微软账号(省略名称时使用主账号) |
|
|
117
|
+
| `-r, --render <mode>` | `on-demand` | 渲染模式:`on-demand`、`always`、`off` |
|
|
118
|
+
| `--java <path>` | 自动选择 | 指定游戏使用的 Java |
|
|
119
|
+
| `--no-java-download` | — | 禁止自动下载 Java |
|
|
120
|
+
| `--memory <size>` | `2G` | 最大堆内存 |
|
|
121
|
+
| `--no-reconnect` | — | 掉线或崩溃后不自动重连 |
|
|
122
|
+
|
|
123
|
+
全局参数 `-v, --verbose` 用于输出调试日志。
|
|
124
|
+
|
|
125
|
+
### 微软正版账号
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
calcite login # 只需执行一次,按提示在浏览器中完成登录
|
|
129
|
+
calcite accounts
|
|
130
|
+
calcite launch mc.example.com -V 1.21.11 --microsoft
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## MCP 服务器
|
|
134
|
+
|
|
135
|
+
在支持 MCP 的客户端(Claude Code、Claude Desktop、Cursor 等)中添加如下配置:
|
|
136
|
+
|
|
137
|
+
```json
|
|
138
|
+
{
|
|
139
|
+
"mcpServers": {
|
|
140
|
+
"calcite": { "command": "npx", "args": ["-y", "@bkm016/calcite", "mcp"] }
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Claude Code 也可以通过命令添加:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
claude mcp add calcite -- npx -y @bkm016/calcite mcp
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
`calcite mcp` 支持 `-r, --render <mode>` 和 `--memory <size>`,用于设置新客户端的默认值。
|
|
152
|
+
|
|
153
|
+
### 工具列表
|
|
154
|
+
|
|
155
|
+
| 工具 | 说明 |
|
|
156
|
+
| --- | --- |
|
|
157
|
+
| `launch_client` | 启动客户端,可指定服务器、版本、离线用户名或微软账号、渲染模式 |
|
|
158
|
+
| `stop_client` | 停止客户端 |
|
|
159
|
+
| `list_clients` | 列出当前管理的客户端 |
|
|
160
|
+
| `get_state` | 获取生命周期阶段与游戏状态(界面、坐标、生命值、维度、帧率、断开原因) |
|
|
161
|
+
| `get_entities` | 获取客户端已接收的实体,可按半径、类型、名称、UUID 过滤 |
|
|
162
|
+
| `send_chat` | 发送聊天消息 |
|
|
163
|
+
| `run_command` | 执行指令,并返回执行期间收到的聊天 |
|
|
164
|
+
| `screenshot` | 渲染并返回 PNG 截图 |
|
|
165
|
+
| `wait_for` | 等待条件成立:聊天匹配正则、实体出现或消失、进入指定阶段 |
|
|
166
|
+
| `get_chat` | 获取聊天记录 |
|
|
167
|
+
| `get_logs` | 获取游戏日志与 Calcite 日志,用于排查崩溃 |
|
|
168
|
+
| `set_render` | 开启或关闭持续渲染 |
|
|
169
|
+
| `respawn` | 死亡后重生 |
|
|
170
|
+
| `install_version` | 预下载指定版本 |
|
|
171
|
+
| `list_versions` | 列出可用版本 |
|
|
172
|
+
| `account_login_start` | 开始微软账号登录,返回验证链接 |
|
|
173
|
+
| `account_login_status` | 查询登录进度 |
|
|
174
|
+
| `account_list` | 列出已保存的微软账号 |
|
|
175
|
+
| `account_remove` | 删除已保存的微软账号 |
|
|
176
|
+
|
|
177
|
+
仅运行一个客户端时,各工具的 `client` 参数可以省略。工具调用失败时返回 `isError` 结果,错误信息格式为 `[错误码] 描述`。
|
|
178
|
+
|
|
179
|
+
## Node.js API
|
|
180
|
+
|
|
181
|
+
```js
|
|
182
|
+
import { Client } from '@bkm016/calcite';
|
|
183
|
+
|
|
184
|
+
const bot = new Client({
|
|
185
|
+
name: 'Bot1',
|
|
186
|
+
version: '1.21.11',
|
|
187
|
+
server: 'localhost:25565',
|
|
188
|
+
account: { type: 'offline', username: 'Bot1' },
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
bot.on('chat', (line) => console.log(line.message));
|
|
192
|
+
|
|
193
|
+
await bot.start(); // 进入服务器后返回
|
|
194
|
+
console.log(await bot.state());
|
|
195
|
+
console.log(await bot.entities({ radius: 32, type: 'minecraft:player' }));
|
|
196
|
+
|
|
197
|
+
await bot.command('say hello');
|
|
198
|
+
await bot.waitFor({ chat: 'hello' }, 10_000);
|
|
199
|
+
|
|
200
|
+
const { png } = await bot.screenshot();
|
|
201
|
+
await bot.stop();
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### `Client` 主要选项
|
|
205
|
+
|
|
206
|
+
| 选项 | 说明 |
|
|
207
|
+
| --- | --- |
|
|
208
|
+
| `name` | 实例名,只允许字母、数字、`-`、`_`、`.` |
|
|
209
|
+
| `version` | 版本号、`release` 或 `snapshot` |
|
|
210
|
+
| `server` | `host[:port]`;省略时停留在标题界面 |
|
|
211
|
+
| `account` | `{ type: 'offline', username }` 或 `{ type: 'microsoft', name? }` |
|
|
212
|
+
| `render` | `on-demand`(默认)、`always`、`off` |
|
|
213
|
+
| `memory` | 最大堆内存,默认 `2G` |
|
|
214
|
+
| `javaPath` / `allowJavaDownload` | 指定 Java 路径 / 是否允许自动下载 |
|
|
215
|
+
| `jvmArgs` / `gameArgs` | 额外的 JVM 参数 / 游戏参数 |
|
|
216
|
+
| `renderDistance` / `maxFps` | 渲染距离 / 帧率上限 |
|
|
217
|
+
| `reconnect` | `false` 表示关闭自动重连,或传入 `{ maxAttempts }`(默认 10) |
|
|
218
|
+
| `startTimeoutMs` | 启动总超时,含下载时间,默认 15 分钟 |
|
|
219
|
+
|
|
220
|
+
### 方法
|
|
221
|
+
|
|
222
|
+
| 方法 | 说明 |
|
|
223
|
+
| --- | --- |
|
|
224
|
+
| `start()` / `stop()` | 启动(进入服务器后返回)/ 停止 |
|
|
225
|
+
| `prepare()` | 仅下载与校验依赖 |
|
|
226
|
+
| `status()` | 生命周期阶段、最近错误、玩家信息 |
|
|
227
|
+
| `state()` | 游戏状态 |
|
|
228
|
+
| `entities(query)` | 实体列表,`query` 支持 `radius`、`type`、`name`、`uuid`、`limit` |
|
|
229
|
+
| `chat(text)` / `command(cmd)` | 发送聊天 / 执行指令 |
|
|
230
|
+
| `screenshot({ keep })` | 返回 `{ png, path? }` |
|
|
231
|
+
| `waitFor(cond, timeoutMs)` | 等待聊天、实体或阶段条件 |
|
|
232
|
+
| `setRender(enabled)` / `respawn()` | 切换持续渲染 / 重生 |
|
|
233
|
+
| `chatSince(seq)` / `logsSince(opts)` | 读取聊天与日志缓冲 |
|
|
234
|
+
|
|
235
|
+
事件:`phase`、`state`、`chat`、`log`、`exit`。
|
|
236
|
+
|
|
237
|
+
此外还导出 `ClientManager`(多客户端管理)、`installVersion`、`startLogin`、`listAccounts`、`removeAccount` 等函数,类型定义随包发布。
|
|
238
|
+
|
|
239
|
+
## 平台与账号
|
|
240
|
+
|
|
241
|
+
| 平台 | 离线账号 | 微软账号 |
|
|
242
|
+
| --- | --- | --- |
|
|
243
|
+
| Linux | 全部功能(在 Xvfb 中渲染) | 全部功能 |
|
|
244
|
+
| Windows / macOS | 无渲染运行,不支持截图,其余功能正常 | 全部功能 |
|
|
245
|
+
|
|
246
|
+
HeadlessMC 仅允许离线账号在 Linux 虚拟显示器中渲染。这是上游策略,Calcite 遵循该策略。如需在 Windows 或 macOS 上截图,请使用正版账号。
|
|
247
|
+
|
|
248
|
+
离线账号只能进入 `online-mode=false` 的服务器。
|
|
249
|
+
|
|
250
|
+
## 渲染模式
|
|
251
|
+
|
|
252
|
+
| 模式 | 说明 |
|
|
253
|
+
| --- | --- |
|
|
254
|
+
| `on-demand`(默认) | 平时不渲染画面,截图时临时渲染。兼顾资源占用与截图能力 |
|
|
255
|
+
| `always` | 持续渲染,适合在本地桌面观察 |
|
|
256
|
+
| `off` | 以无渲染器方式运行(替换 LWJGL),资源占用最低,不支持截图 |
|
|
257
|
+
|
|
258
|
+
## 版本兼容性
|
|
259
|
+
|
|
260
|
+
| 版本范围 | 支持情况 |
|
|
261
|
+
| --- | --- |
|
|
262
|
+
| 1.14.4 及以上 | 全部功能(状态、实体、聊天、指令、截图) |
|
|
263
|
+
| 1.14.4 以前 | 可以启动并进入服务器;Mojang 未发布这些版本的映射表,探针功能不可用 |
|
|
264
|
+
|
|
265
|
+
已验证的版本:1.16.5、1.20.4、1.21.11、26.3。
|
|
266
|
+
|
|
267
|
+
## 数据目录与环境变量
|
|
268
|
+
|
|
269
|
+
所有数据保存在 `~/.calcite`,可通过 `CALCITE_HOME` 修改。
|
|
270
|
+
|
|
271
|
+
| 目录 | 内容 |
|
|
272
|
+
| --- | --- |
|
|
273
|
+
| `minecraft/` | 各版本共享的游戏文件、库与资源 |
|
|
274
|
+
| `instances/<name>/` | 各实例独立的游戏目录(`options.txt`、日志、截图) |
|
|
275
|
+
| `hmc-home/HeadlessMC/auth/` | 已保存的微软登录凭据(权限 600,请妥善保管) |
|
|
276
|
+
| `java/` | 自动下载的 Java 运行时 |
|
|
277
|
+
|
|
278
|
+
| 环境变量 | 说明 |
|
|
279
|
+
| --- | --- |
|
|
280
|
+
| `CALCITE_HOME` | 数据目录 |
|
|
281
|
+
| `CALCITE_LOG_LEVEL` | 日志级别:`debug`、`info`、`warn`、`error`、`silent` |
|
|
282
|
+
| `HTTPS_PROXY` / `HTTP_PROXY` / `NO_PROXY` | 下载代理 |
|
|
283
|
+
| `CALCITE_JAVA_<主版本>` | 指定某个 Java 主版本的路径,例如 `CALCITE_JAVA_8` |
|
|
284
|
+
| `CALCITE_HMC_JAR` / `CALCITE_HMC_URL` | 使用自定义的 HeadlessMC |
|
|
285
|
+
| `CALCITE_PROBE_DIR` | 探针目录,路径中不能包含空格 |
|
|
286
|
+
|
|
287
|
+
## 故障排查
|
|
288
|
+
|
|
289
|
+
错误均带有错误码。CLI 输出格式为 `error [code]: ...`,MCP 返回格式为 `[code] ...`。
|
|
290
|
+
|
|
291
|
+
| 错误码 | 原因与处理 |
|
|
292
|
+
| --- | --- |
|
|
293
|
+
| `server_unreachable` | 服务器端口不可达。请检查地址、端口与防火墙 |
|
|
294
|
+
| `start_timeout` | 未在规定时间内进入游戏。可用 `get_logs` 或 `logsSince()` 查看游戏日志 |
|
|
295
|
+
| `crashed` | 游戏进程退出。错误信息中附有日志末尾内容 |
|
|
296
|
+
| `renderer_unavailable` | 无法创建任何图形后端。Linux 无显卡环境请安装 `libegl1 libegl-mesa0`(或 `mesa-vulkan-drivers`),也可改用 `render: 'off'` |
|
|
297
|
+
| `headless` | 当前客户端以无渲染方式运行,无法截图。参见[平台与账号](#平台与账号) |
|
|
298
|
+
| `not_logged_in` / `unknown_account` | 未登录微软账号或账号名不存在。请先执行 `calcite login` |
|
|
299
|
+
| `instance_busy` | 同名实例已在其他进程中运行 |
|
|
300
|
+
| `unsupported_version` | 版本不存在或不受支持 |
|
|
301
|
+
|
|
302
|
+
排查环境问题时,建议先运行 `calcite doctor`。
|
|
303
|
+
|
|
304
|
+
## 工作原理
|
|
305
|
+
|
|
306
|
+
1. Calcite 解析 Mojang 版本清单,下载客户端、库与资源文件,并逐一校验哈希。
|
|
307
|
+
2. 使用 [HeadlessMC](https://github.com/headlesshq/headlessmc) 启动游戏。每个实例拥有独立的游戏目录和启动参数。
|
|
308
|
+
3. 向游戏注入一个轻量 Java Agent(探针)。探针借助 Mojang 官方映射表定位游戏内部类,并通过本地 TCP 连接与 Calcite 交换 JSON 消息。
|
|
309
|
+
4. 在 Linux 无显示环境中,Calcite 启动共享的 Xvfb,并配置 Mesa 软件渲染。Minecraft 26.x 的渲染器改用 EGL。
|
|
310
|
+
|
|
311
|
+
## 许可
|
|
312
|
+
|
|
313
|
+
本项目以 [MIT](LICENSE) 许可证发布。第三方组件的许可信息见 [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md)。
|
|
314
|
+
|
|
315
|
+
使用 Minecraft 须遵守 [Minecraft EULA](https://www.minecraft.net/eula)。连接正版服务器时,请使用您本人的正版账号。本项目与 Mojang Studios、Microsoft 无关。
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Third-party notices
|
|
2
|
+
|
|
3
|
+
Calcite does not bundle the software below; it downloads it at runtime from the original publishers and
|
|
4
|
+
verifies the published checksums.
|
|
5
|
+
|
|
6
|
+
## HeadlessMC
|
|
7
|
+
|
|
8
|
+
Calcite launches Minecraft through [HeadlessMC](https://github.com/headlesshq/headlessmc) (pinned release,
|
|
9
|
+
SHA-256 verified), which is distributed under the following license:
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
MIT License
|
|
13
|
+
|
|
14
|
+
Copyright (c) 2025 3arthqu4ke
|
|
15
|
+
|
|
16
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
17
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
18
|
+
in the Software without restriction, including without limitation the rights
|
|
19
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
20
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
21
|
+
furnished to do so, subject to the following conditions:
|
|
22
|
+
|
|
23
|
+
The above copyright notice and this permission notice shall be included in all
|
|
24
|
+
copies or substantial portions of the Software.
|
|
25
|
+
|
|
26
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
27
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
28
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
29
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
30
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
31
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
32
|
+
SOFTWARE.```
|
|
33
|
+
|
|
34
|
+
## Minecraft
|
|
35
|
+
|
|
36
|
+
Minecraft game files, libraries, assets and mappings are downloaded from Mojang's servers and are subject to the
|
|
37
|
+
[Minecraft EULA](https://www.minecraft.net/eula) and the
|
|
38
|
+
[Minecraft Usage Guidelines](https://www.minecraft.net/usage-guidelines). Mojang's obfuscation maps are used only
|
|
39
|
+
at runtime to locate game classes and are never redistributed.
|
|
40
|
+
|
|
41
|
+
## Java runtimes
|
|
42
|
+
|
|
43
|
+
When no suitable Java installation is found, Calcite downloads Eclipse Temurin builds from
|
|
44
|
+
[Adoptium](https://adoptium.net) (GPLv2 with Classpath Exception).
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { CalcitePaths } from './paths.js';
|
|
2
|
+
/** HeadlessMC stores Microsoft sessions (refresh tokens) here; Calcite restricts it to the current user. */
|
|
3
|
+
export declare function accountsFile(paths: CalcitePaths): string;
|
|
4
|
+
export declare function accountsLock(paths: CalcitePaths): string;
|
|
5
|
+
export interface AccountInfo {
|
|
6
|
+
name: string;
|
|
7
|
+
uuid?: string;
|
|
8
|
+
/** The account HeadlessMC uses for the next launch. */
|
|
9
|
+
primary: boolean;
|
|
10
|
+
}
|
|
11
|
+
/** Stored Microsoft accounts (no secrets). The first one is the primary account. */
|
|
12
|
+
export declare function listAccounts(paths: CalcitePaths): Promise<AccountInfo[]>;
|
|
13
|
+
export declare function removeAccount(paths: CalcitePaths, name: string): Promise<boolean>;
|
|
14
|
+
export interface LoginHandle {
|
|
15
|
+
/** Microsoft device login URL (contains the code); open it in a browser and approve. */
|
|
16
|
+
url: Promise<string>;
|
|
17
|
+
/** Resolves with the Minecraft profile name once the login completed and the account was stored. */
|
|
18
|
+
done: Promise<string>;
|
|
19
|
+
cancel(): Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Starts a Microsoft device-code login through HeadlessMC. The session (including the refresh token) is stored
|
|
23
|
+
* in the shared HeadlessMC home and refreshed automatically on every launch.
|
|
24
|
+
*/
|
|
25
|
+
export declare function startLogin(paths: CalcitePaths, { timeoutMs }?: {
|
|
26
|
+
timeoutMs?: number | undefined;
|
|
27
|
+
}): Promise<LoginHandle>;
|
package/dist/accounts.js
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { chmod, readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { ensureHmc, ensureHmcHome, killTree, runHmc } from './hmc.js';
|
|
4
|
+
import { ensureLauncherJava } from './java.js';
|
|
5
|
+
import { withLock } from './lock.js';
|
|
6
|
+
/** HeadlessMC stores Microsoft sessions (refresh tokens) here; Calcite restricts it to the current user. */
|
|
7
|
+
export function accountsFile(paths) {
|
|
8
|
+
return join(paths.hmcHome, 'HeadlessMC', 'auth', '.accounts.json');
|
|
9
|
+
}
|
|
10
|
+
export function accountsLock(paths) {
|
|
11
|
+
return join(paths.hmcHome, 'accounts.lock');
|
|
12
|
+
}
|
|
13
|
+
function findProfile(account) {
|
|
14
|
+
// FullJavaSession JSON: { mcProfile: { name, id, ... }, ... } (possibly nested)
|
|
15
|
+
const stack = [account];
|
|
16
|
+
while (stack.length) {
|
|
17
|
+
const node = stack.pop();
|
|
18
|
+
if (!node || typeof node !== 'object')
|
|
19
|
+
continue;
|
|
20
|
+
const obj = node;
|
|
21
|
+
if (obj.mcProfile && typeof obj.mcProfile === 'object') {
|
|
22
|
+
const p = obj.mcProfile;
|
|
23
|
+
return { name: typeof p.name === 'string' ? p.name : undefined, uuid: typeof p.id === 'string' ? p.id : undefined };
|
|
24
|
+
}
|
|
25
|
+
for (const v of Object.values(obj))
|
|
26
|
+
if (v && typeof v === 'object')
|
|
27
|
+
stack.push(v);
|
|
28
|
+
}
|
|
29
|
+
return {};
|
|
30
|
+
}
|
|
31
|
+
async function readAccounts(paths) {
|
|
32
|
+
try {
|
|
33
|
+
const data = JSON.parse(await readFile(accountsFile(paths), 'utf8'));
|
|
34
|
+
return Array.isArray(data.accounts) ? data.accounts : [];
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/** Stored Microsoft accounts (no secrets). The first one is the primary account. */
|
|
41
|
+
export async function listAccounts(paths) {
|
|
42
|
+
return (await readAccounts(paths)).map((a, i) => ({ ...findProfile(a), name: findProfile(a).name ?? `account-${i}`, primary: i === 0 }));
|
|
43
|
+
}
|
|
44
|
+
export async function removeAccount(paths, name) {
|
|
45
|
+
return withLock(accountsLock(paths), async () => {
|
|
46
|
+
const accounts = await readAccounts(paths);
|
|
47
|
+
const kept = accounts.filter((a) => findProfile(a).name?.toLowerCase() !== name.toLowerCase());
|
|
48
|
+
if (kept.length === accounts.length)
|
|
49
|
+
return false;
|
|
50
|
+
await writeFile(accountsFile(paths), JSON.stringify({ accounts: kept }, null, 2));
|
|
51
|
+
await restrictPermissions(paths);
|
|
52
|
+
return true;
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
async function restrictPermissions(paths) {
|
|
56
|
+
if (process.platform === 'win32')
|
|
57
|
+
return; // stays under the user's profile ACL
|
|
58
|
+
await chmod(accountsFile(paths), 0o600).catch(() => undefined);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Starts a Microsoft device-code login through HeadlessMC. The session (including the refresh token) is stored
|
|
62
|
+
* in the shared HeadlessMC home and refreshed automatically on every launch.
|
|
63
|
+
*/
|
|
64
|
+
export async function startLogin(paths, { timeoutMs = 15 * 60_000 } = {}) {
|
|
65
|
+
const java = await ensureLauncherJava(paths);
|
|
66
|
+
const hmcJar = await ensureHmc(paths);
|
|
67
|
+
await ensureHmcHome(paths);
|
|
68
|
+
let resolveUrl;
|
|
69
|
+
let rejectUrl;
|
|
70
|
+
const url = new Promise((res, rej) => {
|
|
71
|
+
resolveUrl = res;
|
|
72
|
+
rejectUrl = rej;
|
|
73
|
+
});
|
|
74
|
+
let failure = '';
|
|
75
|
+
let account = '';
|
|
76
|
+
const run = runHmc({
|
|
77
|
+
javaPath: java.path,
|
|
78
|
+
hmcJar,
|
|
79
|
+
paths,
|
|
80
|
+
props: { 'hmc.store.accounts': 'true' },
|
|
81
|
+
command: ['login'],
|
|
82
|
+
onLine: (line) => {
|
|
83
|
+
const go = /Go to (https?:\/\/\S+)/.exec(line);
|
|
84
|
+
if (go)
|
|
85
|
+
resolveUrl(go[1]);
|
|
86
|
+
const ok = /Logged into account (.+?) successfully/.exec(line);
|
|
87
|
+
if (ok)
|
|
88
|
+
account = ok[1];
|
|
89
|
+
if (/Failed to login|You can't play|Login process cancelled/.test(line))
|
|
90
|
+
failure = line.trim();
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
const timer = setTimeout(() => void killTree(run.child), timeoutMs);
|
|
94
|
+
const done = run.exited.then(async () => {
|
|
95
|
+
clearTimeout(timer);
|
|
96
|
+
if (!account) {
|
|
97
|
+
const err = new Error(failure || 'Login did not complete (timed out or cancelled)');
|
|
98
|
+
rejectUrl(err);
|
|
99
|
+
throw err;
|
|
100
|
+
}
|
|
101
|
+
await restrictPermissions(paths);
|
|
102
|
+
return account;
|
|
103
|
+
});
|
|
104
|
+
done.catch(() => undefined);
|
|
105
|
+
return {
|
|
106
|
+
url,
|
|
107
|
+
done,
|
|
108
|
+
async cancel() {
|
|
109
|
+
clearTimeout(timer);
|
|
110
|
+
await killTree(run.child);
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=accounts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accounts.js","sourceRoot":"","sources":["../src/accounts.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED