feat: 支持多机器人挂机、开拓日志、公屏完整日志与大地图

多机器人(src/bot/botPool.js、src/config/botsConfig.js)
- .env 用 MC_BOTS 一次配置多个账号(JSON 数组或 用户名:密码 逗号分隔),未配置时回退单机器人
- 每个机器人独立连接 / 登录 / 扩地状态机,共享一份领土数据服务与运行日志
- 密码只从 .env 读取;data/bots.json 只存启用状态、备注名、自动开始与各自的配置覆盖
- 每个机器人可覆盖全局配置(策略 / 目标邦国 / 目标数量等),未覆盖字段回退全局默认

开拓日志(src/core/expansionLog.js)
- 逐条记录开拓玩家、邦国、区块、方块坐标、时间与判定来源,追加写入 data/expansion-log.jsonl
- 支持按机器人 / 邦国 / 时间筛选、统计、导出带 BOM 的 CSV,超过 16MB 自动轮转

游戏公屏完整日志与聊天框(src/core/chatLog.js)
- 每个机器人的全部公屏 / 系统 / 动作栏消息按机器人分文件留档,自身发出的聊天与指令同样留档
- 控制台新增公屏聊天页签与消息发送框

登录验证门禁
- 游戏侧:未完成登录验证时拒绝发送指令 / 聊天,isReady() 也不放行扩地任务;
  新增 server.loginConfirmTimeoutMs 兜底,避免服务器不回提示导致永远卡在未登录
- 控制台侧:新增 WEB_PASSWORD 与 /api/login、/api/session,页面登录框验证通过才允许操作

大地图(src/core/bigMapService.js)
- 爬取服务器地图站点(squaremap)的瓦片图片与领土标记,一张图上看全部机器人坐标
- 坐标系对源站实测标定并用 27 个王城交叉验证;瓦片磁盘缓存,层级 0 启动预爬取、更高层级按需穿透
- 领土按 markers.json 原始多边形绘制(预编译 Path2D,even-odd 保留孔洞),叠加王城与机器人标签

配套改造
- TerritoryModel 新增 flyingChunksOf / ownChunksOf,邦国归属改为按名称显式传入,
  不再依赖全局 selfStateName(多机器人会互相覆盖)
- Web 接口以 /api/bots/:id/... 为主,原单机器人接口保留为默认机器人的等价别名
- 新增 scripts/check-web-ids.js 校验前端元素引用一致性

测试从 154 增至 242,全部通过。
这个提交包含在:
lyizai
2026-09-27 21:22:57 +08:00
父节点 223cf719b6
当前提交 39624da2d5
共修改 30 个文件,包含 5480 行新增和 362 行删除
+76 -3
查看文件
@@ -85,7 +85,7 @@ html, body {
/* ==================== 布局 ==================== */
.layout {
display: grid;
grid-template-columns: 300px minmax(420px, 1fr) 360px;
grid-template-columns: 320px minmax(460px, 1fr) 380px;
gap: 12px;
padding: 12px;
align-items: start;
@@ -140,7 +140,7 @@ html, body {
.card-map { display: flex; flex-direction: column; }
#mapCanvas {
width: 100%;
height: 380px;
height: 440px;
background: #05070a;
border: 1px solid var(--border);
border-radius: 8px;
@@ -163,13 +163,86 @@ html, body {
.sw-target { background: #d29922; }
.sw-player { background: #ffffff; }
.sw-capital { background: #bc8cff; }
.sw-bot { background: #ffd33d; }
.chk { display: flex; align-items: center; gap: 4px; font-size: 12px; color: var(--muted); cursor: pointer; }
.hidden { display: none !important; }
.inline-field { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--muted); }
.input-sm { width: auto; min-width: 110px; padding: 4px 8px; font-size: 12px; }
.tabs-inline { margin-bottom: 0; }
.error-text { color: var(--red); }
/* ==================== 机器人列表 ==================== */
.bot-list { display: flex; flex-direction: column; gap: 6px; }
.bot-item {
display: grid;
grid-template-columns: 10px 1fr auto;
gap: 8px; align-items: center;
padding: 7px 9px;
border: 1px solid var(--border);
border-radius: 8px;
background: var(--panel-2);
cursor: pointer;
}
.bot-item:hover { border-color: #48505e; }
.bot-item.active { border-color: var(--accent-2); box-shadow: 0 0 0 1px rgba(47,129,247,.35); }
.bot-item .dot {
width: 9px; height: 9px; border-radius: 50%; background: var(--muted);
}
.bot-item .dot.online { background: var(--green); }
.bot-item .dot.connecting { background: var(--yellow); }
.bot-item .dot.offline { background: var(--red); }
.bot-item .dot.disabled { background: #484f58; }
.bot-item .name { font-size: 13px; }
.bot-item .sub { font-size: 11px; color: var(--muted); }
.bot-item .meta { font-size: 11px; color: var(--muted); text-align: right; white-space: nowrap; }
/* ==================== 公屏聊天 ==================== */
.chat-line { display: block; }
.chat-time { color: #586069; margin-right: 6px; }
.chat-bot { color: var(--accent-2); margin-right: 4px; }
.chat-user { color: var(--purple); margin-right: 4px; }
.chat-out { color: var(--green); }
.chat-command { color: var(--yellow); }
.chat-system { color: var(--muted); }
.chat-action { color: #6e7681; }
/* ==================== 开拓日志 ==================== */
#expView { white-space: normal; padding: 0; }
.exp-table { width: 100%; border-collapse: collapse; font-size: 12px; }
.exp-table th {
position: sticky; top: 0;
text-align: left; color: var(--muted); font-weight: 500;
background: #05070a; padding: 4px 6px;
border-bottom: 1px solid var(--border);
}
.exp-table td { padding: 3px 6px; border-bottom: 1px solid #12161d; white-space: nowrap; }
.exp-table tbody tr:hover { background: #0e131a; }
.exp-empty { color: var(--muted); }
.config-scope { margin-bottom: 8px; }
/* ==================== 登录遮罩 ==================== */
.overlay {
position: fixed; inset: 0; z-index: 200;
display: grid; place-items: center;
background: rgba(5, 7, 10, .78);
backdrop-filter: blur(2px);
}
.overlay-box {
width: min(360px, 92vw);
background: var(--panel);
border: 1px solid var(--border);
border-radius: 12px;
padding: 18px;
}
.overlay-box h2 { font-size: 15px; margin: 0 0 6px; }
.overlay-box .input { margin: 10px 0; }
/* ==================== 日志 ==================== */
.card-log { display: flex; flex-direction: column; }
.log-view {
height: 260px;
height: 300px;
overflow-y: auto;
background: #05070a;
border: 1px solid var(--border);