feat: 用 Node.js + mineflayer 重构 AutoStore,UI 改为网页控制台并适配 Grim 反作弊
由 Fabric 客户端模组 AutoStore v1.3.1 重构为独立 Node.js 机器人,无需游戏客户端。 核心实现: - 领土数据:Dynmap markers.json 拉取解析(奇偶填充识别国中飞地)、SimpCore 开放 API 第四数据源、 带缓存击穿的时间戳请求与内容未变化跳过解析 - 扩地规划:四种策略(方形外扩 / 区域 S 形扫描 / 玩家周围 / 绕国一圈)逐行对照移植, 接壤判定只算己方领土,飞地优先填补 - 扩地状态机:规划→寻路→等待开垦→成功/失败→下一目标→完成,含超时重试、 往边上走两步自救、连续超时回城、耐久保护回城 - 生存辅助:自动进食、自动攻击(豁免中立生物)、自动游泳防溺水、自动用船(默认关闭) - 寻路:Baritone → mineflayer-pathfinder,高度偏好用包装 Goal 等价移植 Grim 反作弊合规层(新增,核心差异点): - 旋转不超前:接管 bot.look 按 ≤8.6°/tick 推进朝向,消除 mineflayer 「本地朝向瞬间跳变、数据包滞后补发」导致的 Prediction 分歧 - 攻击三重校验:朝向已同步 + 距离 ≤3.0 格 + 视线可达 + 攻击冷却 + 非骑乘/进食 - 动作互斥:拦下疾跑+潜行、疾跑+使用物品等原版不可能出现的组合 - 物理参数只读自检 + 寻路约束(禁挖/禁放/禁跑酷/禁搭塔/限下落/绕开水域) 网页控制台(新增): - 状态面板、Canvas 领土地图(缩放/平移/图层)、分组配置表单、实时日志流 - REST + WebSocket 接口,支持 WEB_TOKEN 令牌鉴权 修复: - containsFuzzy 只取固定长度前缀的末行编辑距离,导致完全相同的子串也匹配不上 - 占领去重依赖 Set.add 返回值(JS 中恒为真),导致同一区块被重复计数 - 非法枚举值不再钳制到最近边界,改为回退默认值 测试:154 个用例,npm test 全绿;npm run check 语法自检通过。
这个提交包含在:
@@ -0,0 +1,172 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>AutoStore Bot 控制台</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
<body>
|
||||
<header class="topbar">
|
||||
<div class="brand">
|
||||
<span class="logo">AS</span>
|
||||
<div>
|
||||
<h1>AutoStore Bot</h1>
|
||||
<p>Minecraft 自动扩地机器人 · mineflayer · Grim 合规</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="topbar-right">
|
||||
<span id="connBadge" class="badge badge-offline">未连接</span>
|
||||
<span id="taskBadge" class="badge badge-idle">空闲</span>
|
||||
<button id="btnStart" class="btn btn-primary">开始扩地</button>
|
||||
<button id="btnStop" class="btn btn-danger">停止</button>
|
||||
<button id="btnReconnect" class="btn">重连</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="layout">
|
||||
<!-- ==================== 左栏:状态面板 ==================== -->
|
||||
<section class="column col-left">
|
||||
<div class="card">
|
||||
<h2>连接</h2>
|
||||
<dl class="kv">
|
||||
<dt>服务器</dt><dd id="kServer">-</dd>
|
||||
<dt>玩家名</dt><dd id="kUsername">-</dd>
|
||||
<dt>版本</dt><dd id="kVersion">-</dd>
|
||||
<dt>坐标</dt><dd id="kPos">-</dd>
|
||||
<dt>所在区块</dt><dd id="kChunk">-</dd>
|
||||
<dt>生命 / 饥饿</dt><dd id="kHealth">-</dd>
|
||||
<dt>状态</dt><dd id="kBotState">-</dd>
|
||||
<dt>重连次数</dt><dd id="kReconnect">0</dd>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>任务</h2>
|
||||
<dl class="kv">
|
||||
<dt>状态机</dt><dd id="kTaskState">IDLE</dd>
|
||||
<dt>描述</dt><dd id="kTaskStatus">未启动</dd>
|
||||
<dt>当前目标</dt><dd id="kTarget">-</dd>
|
||||
<dt>队列</dt><dd id="kQueue">0</dd>
|
||||
<dt>已完成</dt><dd id="kCompleted">0</dd>
|
||||
<dt>重试</dt><dd id="kRetry">0</dd>
|
||||
<dt>开垦进度</dt><dd id="kProgress">0%</dd>
|
||||
<dt>连续寻路超时</dt><dd id="kTimeout">0s</dd>
|
||||
<dt>开垦时段</dt><dd id="kClaimTime">-</dd>
|
||||
</dl>
|
||||
<div class="progress"><div id="progressBar" class="progress-fill"></div></div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>领土数据源</h2>
|
||||
<dl class="kv">
|
||||
<dt>markers.json</dt><dd id="kMarkersUrl" class="mono small">-</dd>
|
||||
<dt>最近成功</dt><dd id="kLastFetch">-</dd>
|
||||
<dt>错误</dt><dd id="kDataError">-</dd>
|
||||
<dt>邦国数</dt><dd id="kStateCount">0</dd>
|
||||
<dt>已占领区块</dt><dd id="kClaimed">0</dd>
|
||||
<dt>会话占领</dt><dd id="kSession">0</dd>
|
||||
<dt>己方飞地</dt><dd id="kFlying">0</dd>
|
||||
<dt>SimpCore API</dt><dd id="kApi">未启用</dd>
|
||||
</dl>
|
||||
<div class="row">
|
||||
<button id="btnRefreshMap" class="btn btn-sm">刷新地图</button>
|
||||
<button id="btnFetchAll" class="btn btn-sm">拉取全服领土</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>Grim 合规</h2>
|
||||
<dl class="kv">
|
||||
<dt>合规层</dt><dd id="kGrimEnabled">-</dd>
|
||||
<dt>旋转限速</dt><dd id="kGrimRot">-</dd>
|
||||
<dt>朝向已同步</dt><dd id="kGrimSettled">-</dd>
|
||||
<dt>攻击距离</dt><dd id="kGrimReach">-</dd>
|
||||
<dt>攻击冷却</dt><dd id="kGrimCooldown">-</dd>
|
||||
<dt>已拦下动作</dt><dd id="kGrimBlocked">0</dd>
|
||||
<dt>物理自检</dt><dd id="kGrimAudit">-</dd>
|
||||
</dl>
|
||||
<ul id="grimIssues" class="issues"></ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ==================== 中栏:地图 ==================== -->
|
||||
<section class="column col-center">
|
||||
<div class="card card-map">
|
||||
<div class="card-head">
|
||||
<h2>领土地图</h2>
|
||||
<div class="row">
|
||||
<label class="chk"><input type="checkbox" id="chkFull" checked> 显示全部邦国</label>
|
||||
<label class="chk"><input type="checkbox" id="chkFlying" checked> 标出飞地</label>
|
||||
<label class="chk"><input type="checkbox" id="chkGrid" checked> 网格</label>
|
||||
<button id="btnMapCenter" class="btn btn-sm">回到玩家</button>
|
||||
<button id="btnMapFit" class="btn btn-sm">全图</button>
|
||||
</div>
|
||||
</div>
|
||||
<canvas id="mapCanvas"></canvas>
|
||||
<div class="map-legend">
|
||||
<span><i class="sw sw-self"></i>己方领土</span>
|
||||
<span><i class="sw sw-session"></i>本次占领</span>
|
||||
<span><i class="sw sw-flying"></i>飞地(疏漏)</span>
|
||||
<span><i class="sw sw-target"></i>当前目标</span>
|
||||
<span><i class="sw sw-player"></i>机器人</span>
|
||||
<span><i class="sw sw-capital"></i>王城</span>
|
||||
<span id="mapInfo" class="mono small"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card card-log">
|
||||
<div class="card-head">
|
||||
<h2>运行日志</h2>
|
||||
<div class="row">
|
||||
<label class="chk"><input type="checkbox" id="chkAutoScroll" checked> 自动滚动</label>
|
||||
<button id="btnClearLog" class="btn btn-sm">清屏</button>
|
||||
<button id="btnExportLog" class="btn btn-sm">导出日志</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="logView" class="log-view"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ==================== 右栏:配置 ==================== -->
|
||||
<section class="column col-right">
|
||||
<div class="card card-config">
|
||||
<div class="card-head">
|
||||
<h2>配置</h2>
|
||||
<div class="row">
|
||||
<button id="btnSaveConfig" class="btn btn-sm btn-primary">保存配置</button>
|
||||
<button id="btnReloadConfig" class="btn btn-sm">重新载入</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tabs" id="configTabs">
|
||||
<button class="tab active" data-tab="strategy">策略</button>
|
||||
<button class="tab" data-tab="timing">超时</button>
|
||||
<button class="tab" data-tab="pathing">寻路</button>
|
||||
<button class="tab" data-tab="survival">生存</button>
|
||||
<button class="tab" data-tab="data">数据</button>
|
||||
<button class="tab" data-tab="grim">Grim</button>
|
||||
<button class="tab" data-tab="server">服务器</button>
|
||||
</div>
|
||||
<div id="configBody" class="config-body"></div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>手动指令</h2>
|
||||
<div class="row">
|
||||
<input id="cmdInput" class="input" type="text" placeholder="u claimmode(不带斜杠)">
|
||||
<button id="btnSendCmd" class="btn btn-sm">发送</button>
|
||||
</div>
|
||||
<div class="row">
|
||||
<button class="btn btn-sm" data-cmd="u return">/u return</button>
|
||||
<button class="btn btn-sm" data-cmd="u claimmode">/u claimmode</button>
|
||||
<button class="btn btn-sm" data-cmd="spawn">/spawn</button>
|
||||
<button class="btn btn-sm" data-cmd="list">/list</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<div id="toast" class="toast"></div>
|
||||
<script src="app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
在新工单中引用
屏蔽一个用户