部署到 Debian 服务器时暴露的三个真实缺陷: 1. 「被服务器传送」日志洪水 账号未完成服务器验证时服务端每 tick 强推一次位置,实测 3 分钟刷出 748 行日志, 几十分钟就会冲光 2000 条的日志环形缓冲并把 WebSocket 打满。 现改为首次立即记录、其余按 30 秒窗口聚合成一条,断开连接时刷出未汇总计数。 2. 外站账号绑定流程无法识别 原先只认 /login 与 /register,遇到简幻通这类要求 /auth <UID> <验证码> 或扫码绑定的 服务器时,表现只是「连上→被传送→120 秒后被踢→重连」的静默死循环。 现新增 NEED_AUTH_PATTERN 识别并输出可操作的中文告警(每连接一次), 新增 server.authCommand 模板供有固定验证码的服务器自动过验证。 3. 重连无退避 连续被踢时每 10 秒硬撞服务器。现按指数退避拉长(server.reconnectMaxDelayMs, 默认上限 120 秒),成功进入世界后清零;抽出 computeReconnectDelay 便于测试。 顺带补充 README 的「部署到服务器」章节(Node ≥ 22 要求、私有运行时、pm2、日志分文件、排障表)。 测试从 242 增至 252,全部通过。
AutoStore Bot
Minecraft 自动扩地机器人 —— 由原 Fabric 客户端模组 AutoStore 重构而来: Node.js + mineflayer 实现,UI 从游戏内 GUI 改为网页控制台,并针对装有 Grim 反作弊的服务器做合规适配。
不需要开游戏客户端,一条命令启动,浏览器打开控制台即可开始自动扩地。 支持同时挂多个玩家(机器人)、开拓日志、游戏公屏完整日志与爬取服务器地图的大地图。
npm install
cp .env.example .env # 填入服务器地址与账号密码(支持多个账号)
npm start # 打开 http://127.0.0.1:3081
功能对照
| 原模组功能 | 新版实现 | 说明 |
|---|---|---|
远程拉取 markers.json 领土数据 |
✅ | 带时间戳缓存击穿 + no-cache 头,实测 24 个邦国 / 11.5 万区块 200ms 解析完成 |
| 四种扩地策略 | ✅ | 方形外扩 / 区域 S 形扫描 / 玩家周围 / 绕国一圈 |
| 区域扩地严格 S 形扫描 | ✅ | 起始边取离王城最近的边,由内而外蛇形推进 |
| 飞地(疏漏区块)检测与优先填补 | ✅ | 按 dynmap 奇偶填充规则解析多边形,正确识别国中孔洞 |
| 自动寻路前往目标区块 | ✅ | Baritone → mineflayer-pathfinder,高度偏好启发式等价移植 |
| 寻路失败重试 / 往边上走两步 / 连续超时回城 | ✅ | 状态机与阈值完全一致 |
| 运行时接壤校验、目标有效性校验 | ✅ | 每 tick 校验,避免在无效区块上白费时间 |
| 现实时间限制(默认 11:00-22:00) | ✅ | 改为可配置时段,并支持「到点自动开始」 |
| 监听字幕 / 聊天判定开垦结果 | ✅ | 兼容 title / subtitle / actionBar / Boss 条四条通道 |
| 自动进食 | ✅ | |
| 自动攻击敌对生物(豁免中立生物) | ✅ | 铁傀儡 / 僵尸猪灵永不攻击;末影人 / 蜘蛛默认不打(见下方差异说明) |
| 耐久保护回城 | ✅ | |
| 自动游泳防溺水 | ✅ | 水中持续按住跳跃键上浮 |
| 自动用船过水 | ⚠️ 默认关闭 | mineflayer 无载具物理,Grim 风险高,详见「行为差异」 |
| 实时地图 GUI | ✅ 网页版 | Canvas 绘制,支持缩放 / 平移 / 图层开关 |
| 日志导出 | ✅ | 网页按钮导出到 data/ |
| SimpCore 开放 API 第四数据源 | ✅ | 低频轮询 + 手动全服拉取 |
| Grim 反作弊适配 | ✅ 新增 | 见下方专章 |
| 多机器人同时挂机 | ✅ 新增 | 一个进程挂多个账号,各自独立连接 / 登录 / 扩地,配置可独立覆盖 |
| 开拓日志 | ✅ 新增 | 逐条记录开拓玩家、邦国、区块、方块坐标、时间、判定来源,落盘可导出 CSV |
| 游戏公屏完整日志 + 聊天框 | ✅ 新增 | 全部公屏 / 系统消息按机器人分文件留档,控制台可直接发公屏消息 |
| 大地图 | ✅ 新增 | 爬取服务器地图站点瓦片与领土标记,一张图上看全部机器人坐标 |
| 登录验证门禁 | ✅ 新增 | 游戏内登录 + 控制台登录双重校验,通过后才允许操作机器人与发送消息 |
多机器人同时挂机
配置
在 .env 里一次配好所有账号(密码只从这里读,绝不落代码与配置文件):
# 写法一:用户名:密码,逗号分隔
MC_BOTS=开拓一号:password1,开拓二号:password2
# 写法二:JSON 数组(用户名/密码含逗号冒号时用这个)
MC_BOTS=[{"username":"bot1","password":"p1"},{"username":"bot2","password":"p2","label":"二号机"}]
# 不设置 MC_BOTS 时回退到单机器人
MC_USERNAME=AutoStoreBot
MC_PASSWORD=xxxxxx
启动后控制台左栏会列出全部机器人(连接状态 / 坐标 / 任务状态 / 已开拓数), 顶栏下拉框切换当前操作的机器人。
每个机器人独立的配置
控制台右侧配置表单勾选「仅对当前机器人生效」后保存,即为该机器人写入专属配置覆盖
(存 data/bots.json,不含密码);不勾选则写入全局默认配置。未覆盖的字段一律回退到全局默认。
典型用法:给每个账号指定不同的 目标邦国 与 扩地策略,让它们分工扩张不同方向。
设计取舍
- 共享一份领土模型:
markers.json是全服数据(约 160KB / 11.5 万区块), 没必要每个机器人各拉一遍,因此数据服务是单例、共享给全部控制器。 - 邦国归属按机器人解析:
ExpansionController在start()时把识别到的邦国固化到controller.stateName并写回本次任务配置,规划器不再读全局selfStateName(否则会被最后启动的机器人覆盖,导致 A 机器人按 B 的邦国规划)。 - 「会话新占领」区块是全局共享的:控制台地图的「己方领土」显示的是最近启动的那个机器人的邦国。
开拓日志
src/core/expansionLog.js 逐条记录每一次成功开拓:
| 字段 | 说明 |
|---|---|
t |
时间戳(毫秒),界面按 YYYY-MM-DD HH:mm:ss 展示 |
bot / botId |
开拓玩家(机器人游戏名 / id) |
state |
开拓归属的邦国 |
cx / cz |
区块坐标 |
bx / bz |
方块坐标(服务器回报的精确位置,通用成功文案时为空) |
source |
判定来源:chat(带坐标的聊天消息)/ chat-generic(无坐标的通用文案) |
sessionCount |
该机器人本轮任务的第几个 |
- 落盘:
data/expansion-log.jsonl(追加写入,超过 16MB 轮转为.1) - 内存:保留最近 5000 条供实时查看,磁盘上的历史不受此限制
- 控制台「开拓日志」页签支持按机器人筛选、清屏、导出带 BOM 的 CSV(Excel 打开中文不乱码)
游戏公屏完整日志与聊天框
src/core/chatLog.js 把每个机器人收到的全部消息留档,不只留开垦相关的:
- 公屏聊天(其他玩家发言,含发言人)、系统公告、动作栏消息
- 本机器人发出的聊天与指令(便于对照「指令发出后服务器回了什么」)
- 落盘:
data/chat/<机器人名>.jsonl(每机器人一份,超过 16MB 轮转) - 控制台「公屏聊天」页签可按当前机器人或全部机器人查看、按关键字过滤、导出为纯文本
控制台右下角的「控制台 / 聊天框」可以选择公屏聊天或游戏指令模式发送内容。
大地图
src/core/bigMapService.js 爬取服务器地图站点(本项目部署的是
squaremap)的瓦片图片与领土标记,
把所有机器人画在同一张图上。
坐标系(已对源站实测标定)
squaremap 前端用 L.CRS.Simple + tileSize: 512,瓦片路径为
tiles/<world>/<z>/<x>_<y>.png,并且:
- 瓦片图片固定 512×512 像素;
- 最大原生层级
zoom.max(本站为 3)下 1 方块 = 1 像素; - 因此层级
z每张瓦片覆盖512 × 2^(maxZoom − z)个方块, 瓦片(x, y)覆盖方块区间[x·B, (x+1)·B) × [y·B, (y+1)·B)。
实测标定:本站层级 0 每张瓦片覆盖 4096 方块,全世界(±20480)为 10×10 = 100 张。 用 27 个王城坐标交叉验证——按上式换算,王城所在瓦片的平均海洋像素占比为 28.7%, 而错误假设(256 / 1024 方块每瓦片、整体偏移半张瓦片)分别为 76.0% / 47.3% / 41.6%, 即只有正确公式能让王城稳定落在陆地上。
缓存与爬取
| 层级 | 每瓦片方块数 | 全世界瓦片数 | 策略 |
|---|---|---|---|
| 0 | 4096 | 10×10 = 100 | 启动时自动预爬取 |
| 1 | 2048 | 20×20 = 400 | 按需拉取 + 永久缓存 |
| 2 | 1024 | 40×40 = 1600 | 按需拉取 + 永久缓存 |
| 3 | 512 | 80×80 = 6400 | 按需拉取 + 永久缓存 |
- 磁盘缓存:
data/mapcache/<world>/<z>/<x>_<y>.png,命中即不再回源 - 瓦片由后端代理(
/api/bigmap/tile/:z/:x/:y),避免浏览器直连地图站点的跨域问题 - 领土以
markers.json的原始多边形绘制(预编译成Path2D,按 even-odd 填充保留国中孔洞), 叠加本次会话新占领区块、王城与全部机器人坐标(含名字标签) - 操作:滚轮缩放、拖拽平移、「全世界」/「回到机器人」一键定位、「爬取地图」手动触发预爬取
登录验证门禁
「登录验证后才允许操作」在两侧都做了强制:
游戏侧(src/bot/botManager.js)
canOperate()= 已连接 + 已进入世界 + 已完成登录验证- 未通过时
sendCommand/sendChat直接拒绝并记警告,isReady()也不放行扩地任务 - 登录 / 注册流程自身用
{ internal: true }绕过门禁 - 登录确认兜底:部分离线服登录成功后不回明确提示,
server.loginConfirmTimeoutMs(默认 10 秒)内既没收到成功也没收到失败提示时按「已登录」放行,避免机器人永远卡死; 收到「密码错误 / 登录失败」则标记loginFailed且不放行。设为0可禁用兜底 - 外站账号绑定(如简幻通):服务器要求
/auth <UID> <验证码>或扫码绑定时, 密码无法自动完成,程序会输出明确的中文告警(每个连接只提示一次)而不是静默死循环。 若该服务器提供固定验证码,可在配置的「账号绑定 / 二次验证模板」(server.authCommand)里填写
控制台侧(src/web/server.js)
- 配置
WEB_PASSWORD(或WEB_TOKEN)后,页面弹出登录框,POST /api/login校验通过才解锁 - 所有
/api与 WebSocket 握手都要求凭证(X-Auth-Token头 /?token=/ Cookie) /api/session与/api/login本身免鉴权,否则用户无法登录- 控制台顶栏显示登录状态,可随时退出登录
部署到服务器
本项目已在 Debian 12 上以 pm2 常驻运行验证过,关键点:
1. Node.js 版本要求 ≥ 22
mineflayer 4.39 的 engines 声明为 >=22,用 Node 18 会在运行时出问题。
若服务器上已有别的服务依赖旧版 Node,不要升级系统 Node,装一份项目私有运行时即可:
mkdir -p /opt/autostore-bot/runtime && cd /opt/autostore-bot/runtime
curl -fsSL -o node.tar.xz https://nodejs.org/dist/v24.16.0/node-v24.16.0-linux-x64.tar.xz
tar -xJf node.tar.xz && rm node.tar.xz
ln -sfn /opt/autostore-bot/runtime/node-v24.16.0-linux-x64 /opt/autostore-bot/runtime/current
2. 环境变量
对外提供控制台时,WEB_HOST 必须是 0.0.0.0,并且必须设置 WEB_PASSWORD
(否则任何人访问该端口都能操作你的游戏账号):
WEB_HOST=0.0.0.0
WEB_PORT=78
WEB_PASSWORD=<强密码>
3. pm2 常驻
export PATH=/opt/autostore-bot/runtime/current/bin:$PATH
npm install --omit=dev
pm2 start ecosystem.config.js # interpreter 指向项目私有 Node
pm2 save
pm2 startup systemd -u root --hp /root # 开机自启
ecosystem.config.js 里把 interpreter 显式指向私有运行时,避免 pm2 用系统 Node 启动。
4. 日志分两个文件
data/pm2-out.log 是 stdout(info 级),data/pm2-error.log 是 stderr
(warn 与 error 级都在这里)。排查问题时两个都要看;
控制台页面上的运行日志是内存环形缓冲,包含全部级别,不受这个拆分影响。
5. 排障经验
| 现象 | 原因 | 处理 |
|---|---|---|
| 日志被「被服务器传送」刷屏 | 账号未完成服务器验证,服务端每 tick 强推位置 | 已按 30 秒窗口聚合;看是否有「账号绑定」告警 |
| 连上 120 秒后被踢,反复循环 | 服务器要求外站账号绑定(如简幻通 /auth) |
人工完成一次绑定;绑定后同账号即可自动登录 |
mineflayer 加载报错 / 语法不支持 |
系统 Node < 22 | 用项目私有运行时启动 |
Grim 反作弊适配
这是本次重构最核心的工程问题。mineflayer 是第三方协议实现,它的物理引擎(prismarine-physics)
与行为习惯和原版客户端存在偏差,直接跑在 Grim 服务器上会被 Prediction / Reach / NoSlow / MultiActions
等检查标记。本项目用一层 GrimCompat 合规层把所有对外行为收口:
1. 旋转绝不超前(防 Prediction)
mineflayer 的 bot.look() 会立刻把 bot.entity.yaw 改到目标值,而朝向数据包是按
physics.yawSpeed(约 8.6°/tick)逐 tick 补发的。这会造成:
本地已经朝新方向走了 ← 但服务端还以为你朝旧方向
Grim 的 Prediction 检查正是逐 tick 复算玩家位置并与上报位置比对,这种分歧必然被标记。
做法:接管 bot.look / bot.lookAt,只记录目标朝向,在每个 physicsTick 里把
bot.entity.yaw/pitch 按 ≤ 8.6° 的步长推进。这样「本地朝向」永远等于「服务端已收到的朝向」,
最多差 1 tick。awaitRotationSettled() 可等待旋转真正同步完成。
2. 攻击三重校验(防 Reach / LineOfSight / Post)
attackEntity() 出手前依次确认:
- 朝向已同步 —— 服务端认为你正看着目标(防 Post 检查)
- 眼睛到目标碰撞箱最近点 ≤ 3.0 格 —— 与生存模式实体交互距离一致
- 视线可达 —— 射线检测中间没有实心方块遮挡
- 攻击冷却已好 —— 按手持武器攻速计算(剑 625ms / 斧 1000-1250ms / 空手 250ms)
- 不在骑乘 / 进食 / 使用物品状态
3. 动作互斥(防 MultiActions)
原版客户端不可能出现的组合一律拦下,并计入「已拦下动作」计数供控制台观察:
- 疾跑 + 潜行
- 疾跑 + 使用物品(进食 / 拉弓 / 举盾)
- 疾跑 + 跳跃(默认放行 —— 这是原版合法动作,Grim 预测支持;实测被标记时可开启
grim.blockSprintJump退化为普通跳跃)
4. 物理参数只读校验(防「改物理常数绕过预测」)
audit() 会核对 bot.physics 的 gravity / playerSpeed / sprintSpeed / stepHeight /
airborneInertia / waterInertia 是否仍为原版值,并检查 physicsEnabled、游戏模式、鞘翅飞行状态。
任何一项异常都会在控制台的「Grim 合规」面板里报警。本项目从不修改物理常量,也从不直接写坐标。
5. 寻路约束
| 约束 | 默认 | 原因 |
|---|---|---|
canDig |
关闭 | Grim 的 FastBreak 检查极严 |
放置方块(scafoldingBlocks) |
关闭 | Grim 的 place 类检查极严 |
allowParkour |
关闭 | mineflayer 起跳时机与原版有偏差 |
allow1by1towers |
关闭 | 搭塔过程几乎必被标记 |
maxDropDown |
3 格 | 避免长距离坠落 |
liquidCost |
200(avoid 模式) | mineflayer 液体物理与原版差异最大,优先绕开水域 |
allowFreeMotion |
关闭 | 禁止自由运动 |
与原模组的行为差异(重要)
重构过程中有几处有意为之的取舍,请务必了解:
1. 自动用船默认关闭
mineflayer 使用的 prismarine-physics 没有实现载具物理。上船后 mineflayer 会关闭本地物理预测
(bot.on('mount') → shouldUsePhysics = false),机器人位置完全由服务端下发的船实体位置决定,
只能靠 bot.moveVehicle() 驱动船前进。这意味着无法本地预测船的轨迹,Grim 的 Vehicle 类检查
逐 tick 复算载具运动时极易分歧。
因此 waterMode 默认为 avoid(绕开水域),autoBoat 默认为 false。
用船逻辑已完整实现(扫描水域 → 装备船 → 放船 → 登船 → 航行 → 下船 → 打掉回收),
仅在你实测确认该服务器对船宽容时才建议开启(waterMode: 'boat' + autoBoat: true)。
2. 末影人与蜘蛛默认不打
原模组按原版 AI 条件判断(末影人仅被激怒时、蜘蛛仅黑暗中才反击)。mineflayer 拿不到可靠的
「是否被激怒」与「环境亮度」信息,因此默认一律不打(宁可漏打也不误打)。
需要时可用 combat.attackEnderman / combat.attackSpiders 放开。
3. 新增高危生物跳过
监守者 / 末影龙 / 凋灵默认跳过(combat.avoidDangerousMobs)—— 原模组会攻击它们,
但那基本等于自杀。
4. 开垦时段可配置
原模组硬编码 11:00-22:00,现改为 enforceClaimTime + claimStartHour / claimEndHour。
5. 模糊匹配算法修正
原 Java 版的 containsFuzzy 只取固定长度前缀的末行距离,导致 containsFuzzy('开垦中 50%', '开垦中', 0)
返回 false(连完全相同的子串都匹配不上)。本版按注释所述的语义修正为
「存在编辑距离 ≤ maxEdits 的子串」,并补了回归测试。
安装与运行
依赖
- Node.js 18+(开发与验证使用 Node 24)
- 无需 Java、无需游戏客户端
步骤
npm install
cp .env.example .env
# 编辑 .env 填入服务器地址、账号、密码
npm start
启动后控制台会打印访问地址(默认 http://127.0.0.1:3081),浏览器打开即可。
环境变量
所有敏感信息只放在 .env(已被 .gitignore 忽略,绝不要提交):
| 变量 | 说明 |
|---|---|
MC_HOST / MC_PORT |
服务器地址与端口 |
MC_VERSION |
协议版本,默认 1.21.4 |
MC_BOTS |
多机器人账号列表:用户名:密码 逗号分隔,或 JSON 数组写法 |
MC_USERNAME / MC_PASSWORD |
单机器人兜底(未设置 MC_BOTS 时生效) |
MC_AUTH |
offline(离线服)或 microsoft(正版) |
WEB_HOST / WEB_PORT |
控制台监听地址与端口 |
WEB_TOKEN |
控制台令牌;非本机访问必须设置(页面静态资源不校验,/api 与 WebSocket 握手校验) |
WEB_PASSWORD |
控制台登录密码:配置后页面弹出登录框,验证通过才允许操作机器人的控制台 / 聊天框 |
DYNMAP_BASE / DYNMAP_WORLD |
地图站点根地址与世界目录名(领土数据 + 大地图瓦片) |
SIMP_API_KEY |
SimpCore 开放 API Key(可选) |
网页控制台
打开控制台后:
- 顶栏:机器人下拉选择、连接 / 任务徽标、控制台登录状态、开始扩地 / 停止 / 重连
- 左栏:机器人列表(状态 / 坐标 / 任务 / 已开拓数)、连接、任务、领土数据源、Grim 合规
- 中栏:
- 地图页签 —— 大地图(瓦片 + 领土多边形 + 全部机器人坐标)与 领土地图(区块级)
- 日志页签 —— 运行日志 / 公屏聊天 / 开拓日志
- 右栏:8 个标签页的配置表单(可切换「仅对当前机器人生效」)+ 控制台 / 聊天框
地图图层:己方领土(蓝)、本次占领(绿)、飞地疏漏(红)、当前目标(黄)、机器人(白点 / 黄点)、王城(紫)。
REST / WebSocket 接口
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /api/session |
控制台登录状态(免鉴权,用于决定是否弹登录框) |
| POST | /api/login |
控制台登录(免鉴权) |
| GET | /api/status |
机器人池 / 任务 / 数据源 / 日志 / 大地图完整状态 |
| GET | /api/bots |
全部机器人状态列表 |
| GET | /api/bots/:id/status |
单个机器人状态 |
| GET | /api/bots/:id/settings |
单个机器人的设置与生效配置 |
| POST | /api/bots/:id/settings |
保存备注名 / 启用 / 自动开始 / 配置覆盖 |
| POST | /api/bots/:id/task/start |
启动该机器人的扩地(body 为配置覆盖) |
| POST | /api/bots/:id/task/stop |
停止该机器人的扩地 |
| POST | /api/bots/:id/reconnect |
重连该机器人 |
| POST | /api/bots/:id/command |
向该机器人发送游戏指令(要求已登录验证) |
| POST | /api/bots/:id/chat |
向该机器人发送公屏消息(要求已登录验证) |
| GET | /api/bots/:id/chat |
该机器人的公屏日志(limit / since / kind / keyword) |
| POST | /api/bots/:id/chat/export |
导出该机器人的公屏日志到 data/ |
| GET | /api/expansion-log |
开拓日志(limit / botId / state / since)+ 统计 |
| POST | /api/expansion-log/export |
导出开拓日志 CSV 到 data/ |
| POST | /api/expansion-log/clear |
清空内存中的开拓日志(磁盘保留) |
| GET | /api/bigmap |
大地图元信息(坐标系、瓦片范围、缓存进度、机器人坐标、领土标记) |
| GET | /api/bigmap/markers |
大地图领土标记(多边形 + 王城) |
| GET | /api/bigmap/tile/:z/:x/:y |
瓦片代理(缓存优先,避免跨域) |
| POST | /api/bigmap/crawl |
手动触发批量爬取瓦片 |
| POST | /api/bigmap/cache/clear |
清空瓦片缓存 |
| GET | /api/config |
全局配置 |
| POST | /api/config |
保存并立即应用全局配置 |
| GET | /api/map?full=1&bot=<id> |
领土地图数据(full=1 附带全部邦国区块,bot 指定视角机器人) |
| GET | /api/logs |
运行日志 |
| POST | /api/logs/export |
导出运行日志到 data/ |
| POST | /api/map/refresh |
手动刷新地图数据 |
| POST | /api/api/fetch-all |
手动拉取全服领土(重接口) |
| POST | /api/task/start、/api/task/stop、/api/command、/api/bot/reconnect |
默认机器人的等价别名(兼容单机器人用法) |
| WS | /ws |
实时推送:status(1s)、log、chat、expansion |
配置项
配置保存在 data/autostore.json(全局默认),可通过控制台表单修改;勾选「仅对当前机器人生效」时
写入 data/bots.json 作为该机器人的配置覆盖。完整字段见
src/config/expansionConfig.js,分组如下:
| 分组 | 内容 |
|---|---|
| 策略 | 扩地策略、目标邦国、目标数量、扩圈上限、区域矩形 |
| 超时 | 寻路 / 等待超时、重试次数、回城阈值、走两步轮数、开垦时段 |
| 寻路 | 疾跑 / 游泳 / 跳跃 / 挖方块 / 放方块、高度偏好、跑酷、搭塔、下落高度、液体代价 |
| 生存 | 自动进食、自动攻击、耐久保护、战斗筛选、水域策略、自动用船 |
| 数据 | 地图刷新间隔、SimpCore API |
| 大地图 | 开关、世界名、预爬取层级、最大层级、覆盖半径、启动预爬取、下载并发数 |
| Grim | 合规层全部阈值(见上) |
| 服务器 | 开垦模式指令、登录 / 注册模板、登录确认超时、指令节流、重连 |
开发
npm test # 运行测试(Node 内置 test runner,无需额外依赖)
npm run check # 语法自检(require 全部源码,捕获语法与加载错误)
npm run dev # 文件变更自动重启
测试覆盖
242 个测试用例,覆盖:
- 区块坐标编解码(含负数与边界)
- 领土模型:飞地识别、会话占领、按邦国名取飞地与己方区块、API 数据合并、多边形保留
- 规划器:四种策略、S 形顺序、接壤只算己方领土(历史 bug 回归)、他国区块切断连通、
按
config.stateName解析己方邦国 - markers.json 解析:奇偶填充孔洞、王城换算、颜色解析、多边形扁平化
- 字幕 / 聊天解析:进度、带坐标成功、通用成功、模糊匹配
- Grim 合规层:旋转限速、动作互斥、攻击冷却表、距离 / 视线校验、物理自检
- 战斗筛选:中立生物豁免、条件敌对、猪灵金甲判定、耐久保护
- 寻路服务:Grim 约束是否真正施加到 Movements、高度偏好目标
- 控制器状态机:完整扩地流程、超时重试、走两步、回城、耐久保护停止、完成、 多机器人邦国归属隔离、开拓日志写入与去重
- 多机器人:凭据解析(JSON / 逗号分隔 / 兜底)、机器人池组装、配置覆盖与持久化、 密码不落配置文件、未登录时拒绝发送、全局配置下发保留各自覆盖
- 机器人登录门禁:就绪判定、登录成功 / 失败 / 已登录提示、注册与登录自动补发、 确认兜底超时、公屏消息类型映射
- 开拓日志:字段记录、筛选、统计、JSONL 落盘与重启恢复、损坏行容错、环形缓冲、CSV 导出
- 公屏日志:按机器人隔离、类型 / 关键字过滤、分文件落盘、文件名安全化、文本导出
- 大地图:坐标系换算(含对源站实测标定的王城用例)、瓦片范围、缓存命中、批量爬取、缓存清理
- Web 控制台:地图负载、单 / 多机器人接口、聊天与开拓日志接口、瓦片代理、 令牌与登录鉴权、WebSocket 握手鉴权
目录结构
src/
├── index.js 入口:装配模块、启动 Web 控制台、驱动多机器人 tick
├── config/
│ ├── expansionConfig.js 配置默认值 / 校验 / 归一化
│ ├── configStore.js 全局配置 JSON 持久化
│ ├── botsConfig.js 从 .env 解析多机器人凭据(密码只在这里读)
│ └── botStore.js 机器人设置持久化(不含密码)
├── core/
│ ├── chunkPos.js 区块坐标编解码(整数键,零临时对象)
│ ├── territoryModel.js 领土模型:区块集合、飞地、会话占领、API 合并、多边形
│ ├── territoryDataService.js markers.json 拉取与解析
│ ├── simpApiClient.js SimpCore 开放 API 客户端
│ ├── expansionPlanner.js 四种扩地策略
│ ├── subtitleChatMonitor.js 字幕 / 聊天解析与模糊匹配
│ ├── expansionLog.js ★ 开拓日志(玩家 / 邦国 / 区块 / 时间 / 来源)
│ ├── chatLog.js ★ 游戏公屏完整日志(按机器人分文件)
│ └── bigMapService.js ★ 大地图瓦片爬取与缓存
├── bot/
│ ├── botPool.js ★ 机器人池:同时挂多个玩家
│ ├── botManager.js 连接、登录验证、公屏留档、指令 / 聊天发送
│ ├── grimCompat.js ★ Grim 反作弊合规层
│ ├── pathingService.js 寻路服务(替代 Baritone)
│ ├── autoCombat.js 战斗筛选与耐久检查
│ ├── autoEat.js 自动进食
│ ├── autoBoat.js 自动用船(默认关闭)
│ └── durabilityGuard.js 耐久保护
├── controller/
│ └── expansionController.js 扩地任务状态机(按机器人实例化)
├── web/
│ ├── server.js Express + WebSocket + 登录鉴权
│ └── public/ 控制台前端(原生 HTML/CSS/JS,无构建步骤)
└── util/
└── logger.js 环形日志缓冲
data/ (已 gitignore,运行时生成)
├── autostore.json 全局配置
├── bots.json 机器人设置(启用 / 备注 / 自动开始 / 配置覆盖,不含密码)
├── expansion-log.jsonl 开拓日志
├── chat/<机器人>.jsonl 游戏公屏日志
└── mapcache/<world>/<z>/ 大地图瓦片缓存
许可证
MIT