Skip to content

About

《逃离塔科夫》纯本地实时地图:日志自动识图 + 截图定位 + 悬浮小地图 + 赛季文件刷点,运行时不联网

Topics

Resources

Stars

7 stars

Watchers

0 watching

Forks

Repository files navigation

塔科夫实时地图 (tarkov-offline-map)

Build & Release (Windows) Release License: MIT

《逃离塔科夫》的第三方实时地图辅助工具: 监听游戏日志自动识别当前地图 + 监听截图目录自动定位玩家 + 悬浮小地图。 默认完全本地运行:程序本身不发网络请求、无遥测。v2.0 起提供可选的房间联机 (和队友互相看到位置与标注),需要你自己部署 server/ 里的服务端并填写地址,不填就一行网络代码都不会跑。

下载(Windows 免安装)

到 Releases 下载 tarkov-offline-map-<版本>-win-x64-portable.exe(portable 单文件,双击即用,约 372MB, 内含 15 张地图数据、实验室/迷宫/破冰船的瓦片底图、赛季文件参考截图, 以及 v2.5 的资料库数据(物品/价格/弹药/防具/钥匙/交换/制作/BOSS)与 5442 件物品图标、中文 Wiki 的 1891 张攻略截图 —— 全部离线内置,运行时零网络请求), 校验值见同页 SHA256SUMS.txt。

  • 首次启动会先显示一张启动图:便携版每次启动都要把内置数据(约 330 MB)解压到临时目录, 解压期间看到的就是那张静态启动图,之后才会出现主界面(第二次以后因为系统缓存会快不少)
  • 未做代码签名:SmartScreen 提示"未知发布者"时选择"仍要运行"
  • 游戏需使用无边框/窗口化模式,悬浮小地图才能显示在游戏画面之上
  • 打 tag(v1.2.0 这种)或手动触发 Actions 会自动构建并发布新的 Release

原理

  1. 自动识图:塔科夫每次进局会在 文档\Escape from Tarkov\Logs\log_<时间>_<版本>\ 写入 application_*.log。日志中的

    • scene preset path:maps/<bundle>_preset.bundle(进图加载)
    • Location: <raidCode>(NetworkGameCreate,进局时刻) 即可确定 raidCode → 地图。监听器持续追加读取最新会话日志,自动切换地图。
  2. 截图定位:游戏中按 Print Screen,截图文件名携带玩家坐标与朝向: 2026-09-07[23-05]_58.02, 1.75, 49.47_0.01518, 0.90924, -0.03197, 0.41476_15.47 (0).png → 世界坐标 (x=58.02, y=1.75 高度, z=49.47) + 朝向四元数。 监听截图目录新增文件即在地图上标记玩家位置 + 朝向扇形 + 走过的轨迹。 想让它定时自动刷新就用"设置 → 自动截图":应用隔一段时间替你按一次配置好的截图键 (默认 PrintScreen;键盘注入走系统 API,只在局内且游戏窗口在最前时发,见下文"自动截图"一节)。

全部地图数据为中文(地图/撤离点/Boss/钥匙/物资/地名等),一次快照后完全离线。 转移点标记写的是目的地(游戏数据里的 description,如"前往中心区"),不再只写"转移点"三个字 ——数据里没有 name 字段,早期代码一律落到兜底文案,玩家看不出这个口子通向哪张图。 右侧"标记点"图例面板可按类型配置图钉显示(PMC/Scav 撤离点、转移点、各类物资箱、 Boss、出生点、散落物资、BTR 站点、赛季文件刷点、地名…),与"高级设置"(定位自动缩放/居中、 表层显示全部标记、自动切换图层、声音提示(只用于战局:匹配/匹配到了/进图倒计时,可调"最后几秒")、自动删除截图文件、小地图雷达参数等)均持久化到本地设置文件。 设置页改动即时生效(没有「保存 / 取消」按钮):拖滑块、勾开关当场就变并自动记住; 文本框(目录 / 服务器地址 / 截图键)在回车或点到别处时写入 —— 免得每敲一个字就重启一次日志监听。 设置里的游戏日志目录 / 截图目录除了手输路径,还能点「选择文件夹…」用系统文件夹选择框挑 (选完立刻生效),旁边的「打开文件夹」直接在资源管理器里打开当前路径。

  1. 赛季文件刷点(版本活动找东西):每个赛季有 8 类"赛季文件"(PMC 人员档案 / 医疗 / 财务 / 员工 / 技术 / 蓝图 / 测试 / 项目文件)在各图固定刷点,社区提交 + 官方审核后公开。 快照工具按地图抓取已审核通过的刷点(含参考坐标与类型元数据),地图上以物品图标 + 中文名药丸 + 类型色圆底标出,图例里按文件类型分别开关,点击标记给出中文说明与坐标。 每个刷点还附带社区提交的位置参考截图(419 张原图,webp,约 73MB):点标记后卡片内嵌缩略图, 再点一下弹出大图查看器(滚轮缩放 / 拖动平移 / 双击复位 / Esc 关闭),离线也能一眼看到文件长什么样、 在哪个角落。

  2. 坐标→像素(与原站投影数学一致):

    transform = [0.239, 168.65, 0.239, 136.35]   // 以 Customs 为例
    像素x = rotate(x, z, coordinateRotation).x * transform[0] + transform[1]
    像素y = rotate(x, z, coordinateRotation).y * -transform[2] + transform[3]
  3. 楼层判定:z(高度) 落在各楼层 layers[].extents[].height 区间且位于该层区域矩形内 → 自动切层 (SVG 底图按 data-layer 分组:Ground_Level / First_Floor / Second_Floor / ...)。

  4. 底图有两种:

    • 大多数图用上游的 SVG(data/maps/*.svg),矢量、可无限放大;
    • 实验室 / 迷宫 / 破冰船在上游就没有 SVG,用的是"卫星图"瓦片(tilePath)。 原站这套瓦片的层级是固定 zoom=3(每层 8×8 = 64 块),本项目把瓦片按原样落到 data/tiles/<原始路径>/3/<x>/<y>.png,渲染时按原站同一套几何贴回地图像素空间 (见 src/tiles.js 与 renderer/common/map-view.js 的 satelliteLayout())。 所以这三张图同样完全离线,楼层次级也照常工作(顶栏是楼下拉框,默认「自动」按玩家高度切; 实验室:一层 / 二层 / 技术层,破冰船:16 层甲板按高度从下到上、中文名)。 补数据:npm run fetch:tiles。

离线资料库与中文 Wiki 攻略(v2.5 新增)

v2.5 把"查资料"这件事也搬进了离线包:顶栏多了一个 资料库 按钮,打开一个独立窗口, 里面每个页签都是构建期抓好、随 exe 一起发的本地数据,运行时依然零网络请求。

页签 内容 数据快照
物品 5442 件物品:跳蚤当前价/24h 均价/最低最高/48h 涨跌/报价数、各商人收购价、每格价值、跳蚤解锁等级 data/economy-dump.json
弹药 200 种弹药的穿透/肉伤/甲伤/碎弹/跳弹/精度/后座/初速 同上
防具 383 件头盔/防弹衣/胸挂/附加装甲的防弹等级、耐久、材质、防护部位、各类速度惩罚 同上
钥匙 257 把钥匙的使用次数、重量与价格 同上
藏身处 26 个模块逐级材料清单 + 按当前市价算的升级成本,可勾选已收集 data/market-dump.json
制作 藏身处 428 条制作配方的材料成本 / 产出价值 / 利润 / 每小时利润 同上
交换 1710 条商人交换配方的成本与利润 同上
倒卖 商人买入价与跳蚤价的差价排行 由物品价格现算
BOSS 各图 BOSS 刷新率 data/bosses-dump.json
BTR 森林/街区/灯塔的 BTR 路线与站点:出现时刻、停靠时长、整局时长、刷新率 data/btr-dump.json
收集 任务需要 + 藏身处需要的物品合并清单(数量、市价小计、勾选进度) data/requirements-dump.json + 上面两份
仪式圈 给一个献祭阈值,算出"基准价合计达标、跳蚤成本最低"的物品组合(本地 DP) 由价格现算
特质 赛季特质模拟器:正向/负向、点数预算、冲突提示 data/traits-dump.json

PVE / PVP 是分开的:跳蚤价格在两个模式里差得很远(同一张显卡能差一倍), 资料库顶部有模式切换;默认值来自游戏日志里的 Session mode: Pve 那一行(状态栏显示 "模式: PVE(日志)",设置页可以手动锁成 PVP/PVE)。

任务详情走中文 Wiki:任务卡片里现在直接显示 中文任务描述全文、任务攻略(含社区上传的攻略截图,点图可放大)、物品/钥匙需求、 任务完成对话与奖励;卡片的「中文 Wiki」按钮打开 逃离塔科夫中文Wiki 的对应任务页,英文 fandom 链接降级为次要按钮。任务卡片底部有来源署名与回链。 攻略里的"📍在地图上查看"链接会直接跳到本软件自己的地图,物品名可以跳资料库。

数据与图片都是构建期抓取的(npm run fetch:upstream / fetch:economy / fetch:market / fetch:bosses / fetch:item-icons / fetch:guides / fetch:shots),仓库里带快照,打包后完全离线。 体积参考:攻略截图 124 MB(1891 张,统一重编码到 1600px webp)、物品图标 64 MB(5356 件 × 图标+网格图, 另有 86 件上游就没有图标)、价格与配方 JSON 约 11 MB。 价格会过期,所以资料库右上角一直显示数据时间,发新版本时会重新抓一次。

目录结构

tarkov-offline-map/
├─ main.js                   Electron 主进程(窗口 + 日志/截图监听 + 状态广播 + app:// 协议)
├─ preload.js                contextBridge API
├─ CHANGELOG.md              更新日志(按提交记录手工整理;npm run changelog 可按区间草拟)
├─ src/
│  ├─ constants.js           bundle→raidCode→地图 映射表、正则
│  ├─ maps-data.js           data/maps-dump.json 加载与查询(含本地瓦片底图可用性)
│  ├─ tiles.js               瓦片底图落盘路径规则(远端 tilePath → data/tiles/<目录>)
│  ├─ mini-geometry.js       小地图悬浮窗拖动/钳位几何(纯函数,带单测)
│  ├─ projection.js          投影/四元数/朝向(复刻原站公式)
│  ├─ parsers.js             截图文件名 & 日志行解析
│  ├─ log-watcher.js         日志目录监听(新会话切换 + 追加读 + 启动回补)
│  ├─ screenshot-watcher.js  截图目录监听
│  ├─ auto-shot.js           定时自动截图(模拟截图键)的决策 + PowerShell 按键助手
│  ├─ annotations.js         手动标注存储(清洗/读写,世界坐标)
│  ├─ raid-alerts.js         战局提示音状态机(匹配等待服务器 / 匹配到了 / 进图倒计时最后几秒)
│  ├─ room-client.js         房间联机客户端(连服务端、队友位置/轨迹/标注/勾选任务、新局清残留)
│  ├─ quests-data.js         任务快照加载与统计
│  ├─ json-file.js           JSON 读取(兼容 BOM)
│  └─ room-key.js            房间号推导(sha256,客户端/服务端各一份,交叉校验)
├─ renderer/
│  ├─ common/map-view.js     地图渲染引擎(SVG/瓦片底图·楼层/标记/玩家/轨迹/平移缩放)
│  ├─ map.html|css|js        主地图窗口
│  └─ minimap.html|js        圆形小地图悬浮窗
├─ data/
│  ├─ maps-dump.json         15 张地图完整配置(投影/楼层/撤离点/boss/物资/BTR…)
│  ├─ manual-extracts.json   人工补录点位(上游缺漏:灯塔载具撤离点等 5 条;加载时合并,不会被抓取覆盖)
│  ├─ maps/*.svg             各图 SVG 底图(内含全部楼层 data-layer)
│  ├─ tiles/                 实验室/迷宫/破冰船的瓦片底图(z=3,每层 8×8,约 1230 张 PNG / 10MB)
│  ├─ season-documents.json  赛季文件刷点(419 个点 / 14 张图 / 8 类文件,含中文元数据与参考截图路径)
│  ├─ season-images/         位置参考截图原图(419 张 webp,约 73MB,离线可看)
│  └─ icons/                 标记图标 + season_<类型>.webp 赛季文件图标
├─ tools/
│  ├─ fetch-all.js           数据快照脚本(重新拉取地图配置 + SVG)
│  ├─ fetch-tiles.js         实验室/迷宫/破冰船的瓦片底图下载(原站固定 z=3,约 1230 张)
│  ├─ fetch-season.js        赛季文件刷点快照(含中文名/说明/图标)
│  ├─ fetch-season-images.js 赛季文件位置参考截图下载(原图)
│  ├─ check-svg-pack.js      对比上游互动地图素材包,判断底图是否更新
│  ├─ check-upstream.js      上游数据新鲜度检查(tarkov.dev / 站台版本)
│  ├─ diff-dump.js           两份地图快照逐点 diff(更新后核对差异)
│  ├─ probe-socket.js        按 gameMode 探测站台数据(pvp/pve/赛季)
│  ├─ diagnose.js            诊断真实游戏日志(会话/文件/事件)
│  ├─ verify-exe.ps1         打包版验收(启动/截屏/零残留)
│  ├─ verify-exe-cdp.js      打包版深检(标记/赛季文件/截图查看器/小地图)
│  ├─ verify-mini-input.js   小地图真实鼠标输入验收(拖动/按钮/位置记忆)
│  ├─ verify-raster.js       瓦片底图(实验室/迷宫/破冰船)+ 楼层下拉 + 小地图开关验收(28 项,隔离实例)
│  ├─ verify-exe-tiles.js    打包版同款验收(自造隔离配置目录 + 起 exe + 查版本/雷达/瓦片,6 项)
│  ├─ diagnose-renderer.js   渲染层诊断:窗口白屏/空的时候抓异常与 console 报错(隔离实例)
│  ├─ verify-about.js        关于页面验收(标题改名/纯本地徽标移除/版本号/GitHub 地址/设置里的入口)
│  ├─ verify-annotations.js  手动标注验收(21 项,含常驻工具条/椭圆对角拖拽/Shift 正圆)
│  ├─ verify-mini-anno.js    雷达显示标注验收(8 项:三档配置 + 图例联动)
│  ├─ verify-mini-quest.js   雷达与主地图一致验收(10 项:勾选的任务点也画在雷达上 + 雷达上的字不会整体消失)
│  ├─ verify-raid-alerts.js  战局提示音验收(11 项:自起客户端 + 假日志,验三个时刻响 / 定位与换图不响 / 倒计时落点)
│  ├─ verify-quest-share.js  共享勾选 + 进图要带验收(24 项:自起服务端 + 假队友,验合并显示 / 角标 / 筛选 / 图例 / 黄色高亮)
│  ├─ verify-autoshot.js     定时自动截图验收(15 项,干跑模式,不发真实按键)
│  ├─ verify-raid-reset.js   新一局清场验收(11 项,假日志+假截图走完整管线)
│  ├─ verify-room.js         房间联机界面验收(66 项,含三组队友图例、队友开新局清残留、状态提示行不说假话)
│  ├─ verify-room-live.js    连**你自己部署的服务端**跑真·多客户端自检(N 个真客户端 + 截图定位 + 大图/雷达截图)
│  ├─ verify-room-2clients.js 真·多客户端验收(28 项:自起服务端 + 两个真客户端 + 截图->定位真链路)
│  ├─ verify-server-image.js 不用 Docker 验证镜像内容(文件集/npm ci/HEALTHCHECK/真客户端进房)
│  ├─ make-server-exe.js     把服务端打成 Windows 单文件 exe(Node SEA,自带启动自检)
│  ├─ verify-server-exe.js   服务端 exe 端到端验收(起 exe + 两个真客户端走一遍联机)
│  ├─ preflight.js           发布前闸门(版本一致性/tag/测试/打包产物是否过期/镜像内容)
│  ├─ fake-peer.js           假队友脚本(一台电脑也能看联机效果)
│  ├─ input.ps1              系统级鼠标输入助手(SetCursorPos / mouse_event)
│  ├─ make-changelog.js      按提交记录生成更新日志 / Release 正文(npm run changelog)
│  ├─ release-notes.js       把 CHANGELOG 里这一版拼进 Release 正文(CI 发布时自动用,历史 Release 也能补)
│  └─ simulate.js            用 samples 跑完整管线验证
├─ server/                   房间服务端(v2.0+,可选功能,见 server/README.md)
│  ├─ server.js              HTTP + WebSocket + 房间表 + 命令行参数(纯内存,--persist 才落盘)
│  ├─ protocol.js            协议层纯函数(房间号/帧解析/位置与标注校验)
│  ├─ Dockerfile             极轻量镜像(node:22-alpine,非 root,自带 HEALTHCHECK)
│  └─ docker-compose.yml     一条命令起服务
├─ dist-server/              服务端单文件 exe 的产物目录(npm run dist:server,已 gitignore)
├─ samples/                  真实样本(日志 + 截图)
└─ test/                     node:test 单测(解析器 + 数据完整性)

使用

npm install        # 首次(安装 electron)
npm start          # 启动
npm run smoke      # 冒烟自检(启动 3 秒后自动退出)
npm run visual-test  # 可视化自检:自动注入工厂位置并截屏到 test-artifacts/(主窗口+小地图)

启动后:

  • 自动探测游戏目录(注册表卸载信息 + Steam 常见路径 + 文档目录),也可在"设置"中手动指定
  • 游戏进局后地图自动切换;按 Print Screen 后即见定位(截图文件名携带坐标与朝向)
  • 想让定位定时自动刷新:设置 → 自动截图(定时刷新定位)→ 勾上开关(默认关), 间隔与截图键都可配置(游戏里改过截图键就填同一个)。开启后只在"局内 + 游戏窗口在最前面"时替你有节奏地按一次, 连按 3 次都没拿到新坐标会自动暂停并说明原因
  • 顶栏:地图下拉、楼下拉框(默认"自动"按高度切层)、定位自动居中、固定地图方向(默认亮着;关掉 = 随角色朝向旋转)、小地图雷达、标记点、任务、尺子测距、导入截图、设置; 第二行是常驻的标注工具(画笔/路径/直线/箭头/椭圆/矩形/橡皮 + 颜色/粗细/撤销/清空/取消)
  • 左侧"任务"面板:搜索任务 → 勾选 → 地点画到地图上(详见下节)
  • 右侧"标记点图例"按大类分组,每组前面都有一个批量显示/隐藏的组开关(三态:全开 / 部分选中 / 全关): 撤离·转移·交通 / Boss·出生点 / 钥匙锁·开关 / 危险·固定武器 / 赛季文件刷点 / 物资箱·散落物资 / 地名, 组内再按具体类型单独开关;面板顶部"全开 / 全关"一次控制所有大类
    • 每个大类右上角还有一个 Aa 勾选框:关掉这一大类在地图与雷达上的文字,只留图标 ("只想看图标、不想看一堆字"的用户用得上)。主地图与悬浮雷达共用这一份开关:这边一关, 雷达上同一类的名字也一起消失。没有文字的大类(任务标记 / 玩家·轨迹 / 手动标注 / 队友轨迹 / 队友绘图)那个 Aa 是置灰的,鼠标悬停会说明原因;"地名"本身就是文字,用它左边的勾选框整类隐藏
    • Aa 只管"写不写字",和左边的"这一类还画不画"互不影响:关掉文字后图标一个不少, 全开 / 全关也不会顺手改文字开关
    • "赛季文件刷点"按文件类型分别开关,图标即物品图标,点标记看中文说明、坐标与位置参考截图(可放大)
  • 地图上的地名文字为"白色内色 + 深色外框"(先描边后填充,笔画平滑、与底图对比明显), 大小可在"设置 → 地名文字大小"按 0.8x~2.5x 调整
  • 状态栏显示 最近撤离点 + 距离(迷路时最实用)
  • 关闭主窗口 = 完全退出(小地图雷达一并关闭)

任务侧边栏怎么用(搜索 → 勾选 → 地图上标记)

每一行右侧都有一个「详情」按钮:点它直接弹出任务详情卡(中文说明 / 攻略与截图 / 物品与钥匙需求 / 需求物资市值 / 奖励 / Wiki 链接),和点地图上的任务标记是同一张卡,不用先去地图上找标记。

为什么是手动勾选:游戏日志里拿不到"当前接了哪些任务"的可靠数据(详见下节"关于自动识别"), 所以做法是:把完整任务库(515 个任务 / 608 个区域 / 310 个任务物品刷新点)做成离线可搜索的清单, 你自己勾选在做的,地点就画到地图上。

操作 效果
顶栏「任务」按钮 / 面板右上 × 展开 / 收起左侧面板(状态会记住)
Ctrl+F 直接聚焦搜索框(搜索任务名、目标文字、商人名,空格分隔=多个关键词都要命中)
点任务名 展开目标明细(类型 + 中文描述);有地点的目标右边有「定位」按钮,点了把该地点移到地图中央
点地图上的任务点 弹出任务详情卡(跟赛季文件那张一样):商人/等级/阶段、所属目标、坐标与楼层高度、任务物品、需要哪把钥匙、可交物品清单、前置任务;卡片里能「定位到这里 / 在侧边栏展开 / 打开 Wiki / 勾选此任务」
点任务左侧方框 勾选该任务 → 它的区域立刻画到地图上(勾选状态长期保留,换图/重启都不丢)
面板顶部 chips 本图(只列当前地图有内容的)/ 有地点(只列能画出来的)/ 已勾选(我勾的)/ 队友勾选(房间共享的、队友勾的)/ 击杀区(默认关)。两个勾选筛选是与关系:只开一个 = 只看那一方,两个都开 = 只看我和队友都勾了的(找"一起做"的任务)
两个下拉 按商人、按等级上限过滤
  • 一眼看出这个任务是谁勾的:任务行上有角标——自己勾的是青色 我,队友勾的是他在地图上的颜色 + 昵称 (长昵称截断,悬停看全名);展开明细第一行就是「谁勾选:你 + 阿甘」(房间共享了勾选才有队友); 面板底部统计行也会写 · 队友勾选 N,一眼知道队友那边共享了多少任务。 「队友勾选」筛选在没联机 / 服务端不支持共享时会给出解释性提示(说明需要哪三件事),而不是干瘪的空列表。

  • 分组是 商人 NPC → 阶段:阶段由任务前置链深度自动推导(起始 / 前期 / 中期 / 后期 / 终局), 每行还带 Lv 和 链N 徽标;商人组头显示"已勾选 / 总数"。组头和小节都能点开折叠。

  • 地图上的样式和图例里的小图(swatch)完全一致,统一用橘色 #f59e0b:

    • 橘色半透明多边形 = 任务区域(同色实线边框)
    • 橘色半透明小方框 = 地点标记(15px 见方,就是图例里那个"框";点它弹详情卡)——点它就能看详情
    • 橘色虚线圈 = 任务物品刷新点
    • 早先是"每个任务按 id 分一个颜色 + 实心圆点",地图上会冒出绿/紫圆点,和图例里的橘色框对不上(用户直接截图反馈过);现在统一成橘色半透明
    • 有定位时,不在当前楼层的标记会自动淡化(虚线 + 更透明),不会消失
    • 区域填充透明度默认 0.25(设置里可调);老存档里恰好还是老默认 0.18 的会被自动迁到 0.25,自己调过的不动
  • 地图上只画"已勾选"的任务,不受搜索/筛选影响(否则一搜索标记就全没了,很容易以为勾选丢了)。

  • 击杀类目标给的是刷怪区(很大很糊),默认不画;需要时打开 击杀区 chip。

  • 勾了任务但地图上什么都没出现时,界面会直接说明原因(真实踩过的坑:勾了「铁鸟坠落」, 但当时地图停在灯塔,而它的位置在森林 → 图上空的,很容易以为功能坏了):

    • 任务行上有徽标:位置在 森林(本图没有、别的图有)/ 无坐标(公开数据里没有坐标,只有文字目标)
    • 面板里弹出橙色横幅「勾选的 N 个任务在这张图上没有位置」+ 可点的「切到 森林(2 个点)」按钮
    • 展开明细也会写「这张图(灯塔)没有该任务的位置,位置在:…」并给出切图按钮
  • 公开数据里只有 244/515(47.4%)的任务有坐标;默认不画击杀区时 229/515; 剩下 286 个(55.5%)只有文字目标(如"上交 3 个物品""达到某等级"),这类怎么勾都画不出点——数据本身就如此。

  • 展开任务明细时,最上面是一块黄色高亮的「进图要带」(钥匙 / 要带进图放置·使用的任务物品), 免得开局走到门口才发现钥匙没带:

    • 钥匙:来自目标上的 requiredKeys;一组里有多把时按"或"显示 (宿舍306钥匙 或 宿舍308钥匙、机械钥匙 = 前两把任意一把,另加后面那把)
    • 物品:放置类(plantItem/plantQuestItem)与使用类(useItem)的任务物品,带数量
    • 刻意不列:findItem/findQuestItem(是进图去捡)与 giveItem/giveQuestItem(在任务界面交)—— 列进来只会让清单变长、还误导人
    • 折叠状态的任务行上也会有一个黄色角标(🔑带2 / 📦带1),一眼看出这任务要带东西
    • 同一个任务点开后弹的详情卡里也有同一块(用的同一份纯函数 questBringList)
  • 区域填充透明度在「设置 → 任务标记」里调;本图 过滤是自动的,地图一被识别出来面板就跟着切过去。

  • 详情卡的数据能拿到什么、拿不到什么(都是社区的公开数据,先说清楚免得期待落空):

    • ✅ 中文任务名、目标描述(515/515 与 1441/1441 全覆盖)、商人中文名、等级、前置链深度、Kappa/灯塔标记
    • ✅ 任务物品名、需要哪把钥匙(例:公寓管理员钥匙)、可交/可拾取物品清单(清单里约 87% 有中文名)
    • ✅ 区域坐标 + 楼层高度区间、任务物品刷新点
    • ❌ 每个区域的实景参考截图没有:赛季文件那种"位置参考图"是站点自带的实拍图,任务目标没有对应资源, 所以详情卡给的是"中文描述 + 坐标 + Wiki 链接",不是照片
    • ⚠️ 约 13% 的物品是任务专用、连公开物品表里都没有名字(显示成 未收录物品(短id))

手动标注怎么用(画椭圆 / 规划路线)

标注工具常驻顶栏第二行(不用先点按钮弹出面板):点任意工具就进入标注模式,画的东西按地图保存, 换图/换局/重启都还在。没有"保存/完成"按钮——落笔就自动落盘(600ms 防抖)。

工具 操作
✎ 画笔 按住左键自由涂画(随手圈一下、画个箭头示意)
⌇ 路径 逐点点击,双击或回车结束——规划"怎么绕过去"最顺手
/ 直线 · ➤ 箭头 按住拖:从起点拖到终点
◯ 椭圆 从一个角拖到对角(像 QQ 截图那样,画出来的是拖拽矩形的内接椭圆);按住 Shift 拖 = 正圆
▭ 矩形 从一个角拖到对角
⌫ 橡皮 点一下要删掉的那一笔(线附近 10px 内、椭圆/矩形内部也算)
  • 6 种颜色(红/黄/绿/蓝/紫/白)+ 细/中/粗三档;撤销 退掉上一笔,清空 只清当前地图
  • 快捷键:标注模式下 Ctrl+Z 撤销、回车结束路径;退出标注点顶栏的 「取消」(等价于 Esc, 或再点一次当前工具——工具条本身一直留在顶栏;没进标注时「取消」是灰的)
  • 退出标注后地图恢复拖动与"定位自动居中"(进入标注时只是临时关掉跟随)
  • 标注存的是世界坐标(和截图定位同一套),所以缩放、随朝向旋转、换楼层都不会跑位
  • 存在 %APPDATA%\tarkov-offline-map\annotations.json,与 settings.json 分开; 每张图最多 400 笔、单笔最多 3000 点,超出的部分会被丢掉(防止坏文件把渲染拖死)
  • 图例里有「手动标注 → 我的标注」,可以一键隐藏/显示,计数就是本图笔数
  • 旧版画的圆不再保留:circle 这个类型已经被 ellipse 取代(椭圆更实用),老数据不做迁移, 读入时会被丢掉——这是刻意的(见 CHANGELOG/提交说明)

图例与地图一一对应(硬约束)

右边图例必须覆盖地图上画出来的每一种内容,否则玩家会看到"图上有个图标,图例里找不到":

  • 每个标记组的图标不是固定一个:出生点分 PMC / Scav、Boss 每个头目一张、散落物资分高价值、 物资箱分十几种——图例项会显示该组在当前地图上实际会出现的图标(最多 3 个并排)
  • 任务图层和玩家/轨迹也有图例项:任务区域(实线多边形)、任务物品刷新点(虚线圈)、 玩家位置、移动轨迹、我的标注,用内联小图(SVG)而不是圆点
  • 房间联机时队友的内容分成三个独立分组(见"房间联机 → 地图上怎么看"): 队友位置 / 队友轨迹 / 队友绘图,每组按人一行,可以只关某人的某一样
  • 这些图例项都是真的开关:关掉"任务区域"图层就真的消失,全开/全关 会一次覆盖所有组 (包括别的图上才有的组,不会出现"全关之后切张图又冒出来")
  • tools/verify-quests.js 里有一条自动断言:地图上用到的每个图标都必须在图例里找得到,缺一个就 FAIL

关于"自动识别当前接了哪些任务"(为什么没做)

查过真实日志,结论是做不到可靠,记录在此免得以后重复踩:

  • 我们正在监听的 application_000.log、backend_000.log 完全没有任务数据 (backend 只记录请求的 URL,responseText: 后面的响应体是空的)
  • 同一个会话目录里的 output_000.log(Unity 的 Player.log 拷贝)里能抓到任务 ID: <b>Quest.</b> Can't find condition for target <ID> quest id: <ID>、 Counter with id <ID> can't be found for quest <ID>、ITEMS_TO_DROP 物品清单。 其中 quest id 跨会话完全稳定(两次会话都是同一批 27 个),但这些 ID 在公开任务数据里一个都查不到 (tarkov.dev 515 个任务 0/27 命中,且数据集里有比它们更新的 ID),疑似新版"任务链/主线任务"命名空间; 日志也给不出任务状态(进行中/可接/已完成)和名称
  • 所以:勾选是主干,自动识别是未来的增益层。手头能做的自动化已经做了—— 当前地图、楼层、面板跟随都是自动的;日志里的 27 个 ID 也可以先埋点,等数据源补齐再回填。

圆形小地图雷达怎么用

雷达上默认没有任何按钮:所有开关都在"设置 → 圆形小地图雷达"里调,拖一下就立刻生效 (大小 / 透明度 / 显示半径都是实时变化的,不用点保存)。

操作 效果
按住圆盘任意位置拖动 移动悬浮窗位置(松手记住,重启后还在原处;拖出屏幕会自动钳回)
滚轮 缩放(以光标为中心),一直可用
点击地图空白/标记 不改变视野:雷达始终跟随玩家,不会"点一下地图就飞走"
Tab / 空格 / 回车 与雷达完全无关(窗口 focusable:false,唯一点得到的"解锁"小块也是 tabindex="-1")
设置项(设置 → 圆形小地图雷达) 默认 说明
启用小地图雷达 关 开启独立圆形小地图窗口
整体透明度 0.9 默认"有一点点透明",0.2~1 可调
雷达窗口大小 300 圆盘边长 180~560(屏幕像素);以圆盘中心为基准放大/缩小,你盯着的那块地图不会跳
显示半径(米) 55 圆盘铺满多少米(也就是雷达看多远);改大小/改半径都会立刻按这个数字重新铺满圆盘
随角色朝向旋转 关 关 = 地图方向固定(正北朝上,不随视角变化)
定位后自动居中 开 关掉后只更新玩家点与轨迹,不再把视野拉回玩家;开着时每一次新的定位都会重新居中(把 Ctrl 平移出来的偏移归零)
按玩家高度自动切换楼层 开 关掉后固定显示地图基础层
点击穿透 关 开 = 雷达看得到、点不着(鼠标直接作用到游戏)
缩放跟随互动地图 关 关 = 按自己的显示半径
雷达上显示标注 我的 + 队友的 不显示 / 只显示我的 / 我的 + 队友的:雷达上也画标注(仍受右侧图例开关控制)

鼠标操作(雷达上没有任何常驻按钮):

操作 效果
按住圆盘拖动 移动悬浮窗位置(位置自动记忆)
按住 Ctrl + 拖动圆盘 平移圆盘里面的地图(窗口不动;玩家照旧跟随,只是不再固定在圆心,相当于往某侧多看一点)
Ctrl + 双击 视野偏移归零(回到以玩家为中心;换图/新一局时也会自动归零)
滚轮 缩放雷达(保持光标下的地图点不动)

平移量按 屏幕位移 / 缩放 换算(含"随角色朝向旋转"时的逆变换),与主窗口的地图拖动共用同一份数学。 平移时圆盘边缘会变成琥珀色圆环,和 Cyan 色的"移动窗口"区分开。 点击穿透状态下窗口收不到鼠标,要先点右下角「解锁」再拖。

平移只是"临时往旁边多看两眼":下一次按 Print Screen 定位(位置真的变了)时,视野偏移会自动归零、 玩家回到圆心 —— 所以不会再出现"拖过雷达之后再定位,玩家一直停在偏心位置"。 想一直偏心看某处就关掉「定位后自动居中」,那时定位只更新玩家点、视野一格都不动。

两种手势都由主进程按 12ms 轮询真实光标驱动(拖动窗口是 setBounds 搬窗口,平移是推送光标位置给渲染层)。 渲染层的 pointermove / setPointerCapture 在这块透明无边框窗口上不可靠:光标一离开圆盘事件就断, 表现为"按住 Ctrl 拖,地图只动一点点"。

上一局的轨迹不会带到新局:日志里出现进图行(scene preset path: / TRACE-NetworkGameCreate)时清空玩家位置与轨迹, 手动换图同样清空。只清"比这次进图更旧"的定位,所以应用重启/重连时回放历史进图行不会误清当前这一局 (app.log 会记 new raid (...): 清空轨迹 N 点 + 玩家位置)。

点击穿透(看得到点不着)+「锁 / 解锁」小按钮:两个按钮都在雷达右下角,鼠标靠近才出现(平时完全透明不挡地图)。

  • 未锁定:鼠标放在雷达上 -> 淡出显示「锁」,点它开启点击穿透(鼠标直接作用到游戏)
  • 已锁定:鼠标放在雷达上 -> 淡出显示「解锁」,但鼠标仍旧穿透;把鼠标移到这个小条上才会临时接管鼠标, 点一下「解锁」即关闭穿透并写回设置
  • 也可以在"设置 → 圆形小地图雷达 → 点击穿透"里直接开关

(实现:穿透状态下 Windows 不会把真实鼠标移动转发给渲染层 —— setIgnoreMouseEvents(true,{forward:true}) 实测收不到 mousemove,所以"放在雷达上就显示"的命中判定由主进程按光标 60ms 轮询, 和拖动用的是同一套办法:圆盘内 -> 只显示按钮;小条上 -> 才 setIgnoreMouseEvents(false) 接管鼠标。)

雷达上的图标与主窗口完全一致:只画图标本体,不加任何底盘 / 圆形背景(撤离点就是那块绿色盾牌图标、 Boss 就是头像、钥匙就是钥匙、赛季文件就是文件图标),大小跟随"设置 → 标记大小", 默认比早期版本放大约 2.4 倍,主窗口与雷达共用同一套图例开关。 赛季文件刷点同样标在小地图上(找文件不用切回主窗口)。

勾选的任务点也画在雷达上(任务区域多边形 + 物品刷新点虚线圈):和主窗口读同一份 data/quests-dump.json、同一份勾选状态、同一个透明度与"显示击杀区"开关,两边永远一致; 换图或勾选变化时才重算图层(状态推送很频繁,不做每帧重算)。 转移点文字同样会补上中文目的地(用和主窗口同一份"地图 id → 中文名"字典)。 "设置 → 定位与显示 → 表层显示全部标记"也同时作用于两个窗口。

标注也能画在雷达上(默认就画"我的 + 队友的",可在"设置 → 圆形小地图雷达 → 雷达上显示标注"里 切成"只显示我的"或"不显示"):主窗口画完一笔,雷达立刻跟着出现;右侧图例里关掉 我的标注 或某个人的 队友绘图,两个窗口会一起隐藏(图例开关是共用的)。 雷达窗口很小、标注太密时可以只留自己的或干脆关掉。

为避免小圆盘里"糊成一团",雷达会按视口裁剪并按"重要度 + 离圆心距离"降噪:

  • 标记数超过 90 个时,丢掉最不重要的、最远的(散落物资、各类物资箱 → 远处的地名…), 只保留撤离点/Boss/转移点/钥匙锁/开关/危险/固定武器/赛季文件/BTR 站点等关键点, 以及离你最近的那几个地名
  • 再超过 260 个(还没定位、视野被拉到很宽时)同样按重要度 + 距离硬截断
  • 关键标记的中文名最多同时标 6 个,超过时取"最重要的 + 最近的"若干个 (旧版是"超过 6 个就一个名字都不写",于是把半径调大或走进撤离点密集区时, 雷达上的字会整体消失、来回跳——已修)
  • 主窗口不受影响:地图上依旧是全量标记,图钉开关也对两个窗口同时生效

还没定位过(没按过 PrintScreen)时,雷达以地图中心 + 显示半径作为初始视野, 而不是缩到整张图(否则上千个标记会糊在一起)。

配置文件:%APPDATA%\tarkov-offline-map\settings.json(开发与打包版共用) 运行状态转储:%APPDATA%\tarkov-offline-map\state.json(排查识别/定位问题用) 小地图窗口日志:%APPDATA%\tarkov-offline-map\mini.log(窗口被系统吞掉/崩溃/自动重建都会记录) 地图识别日志:%APPDATA%\tarkov-offline-map\app.log(会话切换/切图/认不出来的图,见下)

战局提示音(只在这三个时刻响)

提示音只用于战局节奏,三个时刻各一种音色(设置 → 提示与行为 里可总开关 + 调"最后几秒"):

| 时刻 | 音色 | 日志依据(|application| 后的消息开头) | 实测间隔 | |---|---|---|---| | ① 开始匹配(在等服务器) | 一声低音 | Matching with group id: N | — | | ② 匹配到了 | 三声上行 | MatchingCompleted: | ① 之后 197~209 秒 | | ③ 进图倒计时的最后几秒 | 短促滴一声(3/2/1 各一次) | 倒计时从 GameSpawned: 开始,GameStarting: 是结束 | GameSpawned → GameStarting 10.3 秒(4 局全一样) |

  • 截图定位、队友位置、换图都不会响 —— 这些是常态高频事件,响起来只会烦人(旧版"进图/定位各响一声"已删掉)
  • 倒计时的几声落在两条日志之间,所以主进程按"GameSpawned + 实测 10.3 秒"排定时器; GameStarting 比预计来得早(组队里别人先加载完)时,没响完的会立刻补一声,不会静悄悄进图
  • 默认"最后 3 秒"开始响(1~10 秒可调);应用启动/重连时回补的历史日志(回扫 2MB) 里那些几分钟前的匹配行不会补响一串
  • 每次响铃都会写进 app.log([alert] 响铃 match-queue / ... countdown(还剩 2 秒)), 想核对时机直接看日志时间戳

实测时间线(1.1.5.1.47510,PvE,4 个会话 6 局;完整原行在 test/raid-alerts.test.js 里):

Matching with group id: N          开始匹配(等待服务器)
  +1.7s    scene preset            (已经在预载地图)
  +16~28s  LocationLoaded
  +197~209s MatchingCompleted      匹配到了
  +0.5s    GamePrepared/GameCreated
  +17~18s  GamePooled
  +7s      GameRunned → GameSpawn → PlayerSpawnEvent
  +10.3s   GameSpawned             倒计时开始(最后 3 秒响)
  +9.4~10.3s GameStarting          倒计时结束 / 开始进入地图
  +12s     GameStarted             已经在局内

地图识别怎么工作 & "没切图"怎么排查

进图时游戏会往最新会话目录的 * application_*.log 写这样一行:

2026-09-18 21:21:48.057|1.1.5.1.47473|Info|application|scene preset path:maps/shopping_mall.bundle rcid:Shopping_Mall.ScenesPreset.asset

程序按 bundle 名 → raidCode → 地图 key 两级映射切图;bundle 名认不出来时再用同一行的 rcid: 兜底。 注意 14 张图里有 13 张是 xxx_preset.bundle,只有立交桥是 shopping_mall.bundle(不带 _preset)。 早期版本这里写死拼 _preset 去查表,于是立交桥永远查不到 → 进图不切图(现在两种写法都支持)。

app.log 里能直接看到判定过程:

日志行 含义
log session: log_2026.09.18_21-00-14_1.1.5.1.47473 正在跟踪哪个游戏日志会话
map switch -> interchange (立交桥) by scene-preset raidCode=Interchange 切图成功(含来源与 raidCode)
UNKNOWN map bundle: xxx (rcid=Yyy) 游戏改了图名,需要补映射表(把这一行反馈即可)
UNMAPPED raidCode: xxx raidCode 认出来了,但没对应到地图

另外两点加固:应用在局内才启动时会回扫日志尾部(最多 8MB)找最后一条地图行,所以中途开程序也能立刻对上当前图; 会话目录消失(游戏清理日志)时会松开文件句柄并报 no-session,不会攥着已删除的文件。

还有一条真实事故(2026-09-19 20:33,已修)——"开着程序再启动游戏,这一整局永远不切图":

时刻 事件
20:33:06.788 游戏创建会话目录 log_2026.09.19_20-33-06_1.1.5.1.47510
20:33:07.020 程序 700ms 轮询看到目录 → 切到该会话,此时 application_000.log 还不存在
20:33:07.683 游戏才创建 application_000.log

监听器原先只在"切换会话"那一次打开日志文件,扑空之后这个会话就永远没有尾巴: 无论你之后进哪张图、写多少日志,程序都读不到 → 表现就是"进图不切图、定位也不动", 只有等下次游戏重启换了目录才自愈。现在每次轮询都补开新出现的 application_*.log, 并锁了回归测试(test/log-watcher.test.js:目录先建、日志文件晚一步才建,也必须读到进图行)。

还有一条更隐蔽、影响更大的(同日现场抓到,已修)——任何一次设置保存都会让监听器瞎掉:

  • config:set 里原来是无条件 syncWatchers() → logWatcher.setRoot() = stop() + start()
  • stop() 把文件尾巴关掉;而 currentDir 没变,scan() 不会走"切换会话"分支
  • → 不会重新打开日志文件 → 这个会话从此读到 0 行,直到游戏下次换会话才自愈

也就是说:局内拖一下小地图、切一个图例、勾一个任务(任何一次 config:set)之后, "进图不切图"就必然发生。现在 syncWatchers() 只在 logsPath / screenshotsPath 真的变了时才重建监听器;另外"补开会话目录里后出现的日志文件"也不再重放历史进图行 (重放会把地图抢回上一张图,并和界面保存设置形成 700ms 死循环——现场 app.log 里能看到 map switch -> woods / map switch -> shoreline / log session 每 0.7 秒刷一轮)。

设置页现在改成即时生效(拖一次滑块会发很多次 config:set),所以上面这条修复 更是硬前提:只要监听器不是"路径真的变了才重建",调一下透明度就会把日志尾巴弄丢。 文本框(目录 / 地址 / 截图键)因此仍然只在 change(回车或失焦)时写入,不做逐字符生效。 回归测试:test/log-watcher.test.js 的「重开不重放历史进图行,尾巴也不丢」。

小地图雷达"消失"问题(已加固)

悬浮雷达是无边框 + 透明 + 置顶窗口,Windows 上这类窗口有几个已知坑,程序里都做了处理:

现象 原因 处理
点一下雷达就"没了" 透明表面在被点击/激活后可能停止重绘:窗口还在,但一片空白 显示/悬停/拖动松手时主动 invalidate() 强制重绘,另加 2.5s 看门狗兜底
按过 Tab 后雷达消失 雷达窗口能拿到键盘焦点,Tab 在它的按钮间循环,空格/回车又把开关切一次 雷达窗口 focusable:false(系统层面就不给键盘焦点)+ 按钮 tabindex="-1" + keydown 拦截 Tab/空格;主窗口顶栏按钮点完即 blur();v1.2.4 起雷达上干脆没有任何按钮
拖不动 / 只能待在右上角 无边框窗口没有标题栏,也没有实现拖动 按住圆盘任意位置即可拖动;由主进程按真实光标位置 setBounds(带尺寸)实现,指针移出窗口也不丢,位置写入配置
拖着拖着雷达越变越大 Windows 150% 缩放下反复 setPosition(DIP↔物理像素取整)每次让尺寸多算 1px 拖动改用 setBounds 每帧钉死当前雷达尺寸(默认 300×300,设置里可调);松手与 2.5s 看门狗再校正一次(mini.log 会记 watchdog: size WxH -> 300)
被游戏窗口盖住 / Win+D 最小化 置顶层级丢失或被系统最小化 看门狗 + blur/focus 事件重新抬高到 screen-saver 级;被最小化立即 restore()
窗口真的被销毁 / 渲染进程崩溃 透明窗口 OOM、GPU 掉线 render-process-gone / did-fail-load 自动 reload;窗口没了自动重建;按钮变黄提示
按钮显示开着但其实没窗口 状态不同步 主进程广播 miniStatus,按钮反映真实状态;再点一次是"恢复"而不是"关闭"
按住 Ctrl 拖动却变成"移动窗口" 雷达窗口 focusable:false(键盘焦点在游戏那边),渲染层 pointerdown 里的 e.ctrlKey 实测可能是 false 按下时直接问 Windows(常驻 PowerShell 助手 [System.Windows.Forms.Control]::ModifierKeys,毫秒级往返),e.ctrlKey 只当快速路径;mini.log 里 probe {"ev":"down","ctrl":...} 会记下渲染层看到的值
松手后雷达还跟着鼠标跑十几秒 只处理了"平移"的收尾,漏掉窗口拖动的 pointerup → 主进程轮询一直跑到 15s 超时(mini.log 记 drag end (timeout)) pointerup / pointercancel / 失焦一律两种手势都收尾;两种手势互斥(开始一个先结束另一个)
Ctrl + 双击没反应 pointerdown 里 preventDefault() 之后 Chromium 不再派发兼容鼠标事件(含 dblclick) 不依赖 dblclick:自己按"两次 Ctrl 按下(450ms / 8px 内)"判定双击

房间联机(v2.0,可选)

默认关闭:不填服务器地址,客户端一行网络代码都不会执行(离线优先是硬承诺)。 开了之后,同一个房间里的人能互相看到位置、朝向、轨迹和手动标注。

你的客户端 ─┐
队友的客户端 ┼── WebSocket(JSON,一条连接)──> 自建服务端(仓库 server/)
队友的客户端 ┘                                   ├─ docker compose / docker run(推荐)
                                                 └─ 或 Windows 单文件 exe(双击就开,见下)

三步上手

# 1) 起服务端(任一方式)
cd server && docker compose up -d            # 推荐(Linux/NAS/软路由)
# 或者:docker run -d -p 8787:8787 --restart unless-stopped ghcr.io/neppure/tarkov-offline-map-server:2.2.0
# 或者(Windows 不想装 docker):下载 Release 里的 tarkov-offline-map-server-<版本>-win-x64.exe,双击启动
#      窗口里会直接打印该填什么(服务器地址 = 你的内网 IP,端口 = 8787)
# 或者:cd server && npm ci --omit=dev && PORT=8787 node server.js
  1. 客户端顶栏 设置 → 房间(联机):填 服务器地址(内网 IP 或域名,例如 192.168.1.10) 与 房间号(你们商量的暗号,建议 6–8 位随机字符,口令可选)→ 点 测试连接(会显示服务端版本) → 点 加入房间。顶栏会出现 在线 · N 人 的小胶囊。
  2. 队友按同样的地址和房间号加入即可。

端口要放行:Windows 防火墙 / 云服务器安全组允许 8787(或你映射的端口)。

⚠️ 别把自己那份配置复制给队友(整份 %APPDATA%\tarkov-offline-map\ 拷过去)。 每个人的"身份"是各自客户端生成并记在配置里的(room.peerId),抄过去就等于告诉服务端 "我们是同一个人",后进来的会把先进来的踢下线 —— 表现是两边都一直「在线 · 1 人」、 永远看不到队友,被踢的那边状态栏写「连接失败:相同身份在别处重连」。 让队友自己装一遍、自己填昵称就行。

一台电脑怎么自己试

不用两台机器,也不用 Docker:

# 窗口 1:起服务端(用的是仓库里的 ws 依赖,不需要装别的东西)
npm run room                       # = node server/server.js,默认 8787 端口(也支持 --port/--persist 等开关)

# 窗口 2:起客户端
npm start
# 设置 → 房间(联机):服务器地址 127.0.0.1、端口 8787、房间号随便填(例如 测试房)、昵称随便
#   点「测试连接」→ 显示服务端版本 → 点「加入房间」,顶栏出现「在线 · 1 人」

# 窗口 3:放一个"假队友"进来(脚本客户端,走的是同一套联机代码)
npm run room:peer -- --room 测试房 --nick 假队友 --map customs
#   它会在海关地图中心附近绕圈走并画一个圈:
#   你那边能看到它的标记(首字"假" + 朝向箭头 + "假队友 · 刚刚")、虚线轨迹和一个粉色圈,
#   右侧图例出现「队友位置 / 队友轨迹 / 队友绘图」三行(都在"假队友"名下),
#   关掉"队友绘图"他那个圈就没了、关掉"队友位置"他的标记就没了(轨迹不受影响)

想同时开两个真客户端自测,用 TAKOV_USER_DATA 给第二个实例换一份配置目录:

$env:TAKOV_USER_DATA="$env:TEMP\takov-alt"; npm start     # 第二个实例(另一份 settings.json)

连这套"服务端 + 两个真客户端"的完整流程也有一键验收(脚本自己起服务端、自己拉两个客户端、 顺手往截图目录扔两张带坐标的假截图验证"定位 -> 房间 -> 对方地图"这条链路,跑完全收掉并还原配置):

node tools/verify-room-2clients.js        # 28 项:互看/真定位同步/轨迹/标注同步/按人开关/离开房间后共享标注与勾选一起下线、重新进房又出现

会共享什么

共享 说明
我在哪张图 换图/进图各上报一次,队友能知道"他在立交桥"(即使还没定位)
我的位置 + 朝向 按 Print Screen 那一刻的定位(和本地定位同一套坐标),不是实时跟随
我的轨迹 最近 200 个定位点,队友图上画成同色虚线,能看出你从哪边过来的
我画的标注 画笔/路径/直线/箭头/椭圆/矩形,实时同步;进房时会把当前这张图上你画过的补发一次
我勾选的任务 整份任务 id 列表(默认开,可在设置里关)。队友图上会画出你勾的任务;两人都勾了同一个任务时只画一次(合并显示),鼠标悬停能看到是谁勾的
昵称 地图上用昵称第一个字 + 朝向箭头画出来;重名会补短 id(小明#3f2)

不共享:游戏日志、截图文件、图例开关、设置、你的任何本地文件。 服务端只转发上面那几样;房间号在传输前已哈希,不在 URL 里、日志里也只打前 6 位。

共享勾选任务是加能力(服务端 welcome 里声明 caps: ['quests']),没有升协议大版本: 新客户端连老服务端 = 这项功能静默关闭(位置/标注照旧),老客户端连新服务端 = 忽略不认识的字段。 想用这个功能要把 server/ 一起更新(docker compose up -d --build / 重新发 exe)。

地图上怎么看

  • 队友标记 = 圆底 + 昵称首字 + 朝向箭头,下面写 昵称 · 多久以前; 超过 2 分钟淡化、超过 10 分钟更淡 —— 因为位置是"他最后一次按截图键"时的,不是实时的
  • 点队友标记 → 视野跳到他那儿(他在别的图就先切过去)
  • 右侧图例里队友的内容分成三个分组:队友位置 / 队友轨迹 / 队友绘图, 每组一个人一行(peer:pos:<id> / peer:trail:<id> / peer:anno:<id>), 可以只关掉某人的某一样:关掉"队友轨迹"他的点还在,关掉"队友位置"轨迹与标注也还在 (地图上画了什么,图例里一定能单独关掉 —— 这是本项目的硬约束)
  • 队友勾选的任务画在同一个任务图层里,图例的「任务标记」组里会多出每人一行的 「XX勾选的任务」(quest:peer:<id>,颜色就是他在地图上的颜色)。规则:
    • 你和他都勾了同一个任务 → 只画一次(合并),悬停显示「任务名(你 + 阿甘 勾选)」
    • 只被他勾的任务 → 关掉他那行就一起隐藏;只被你勾的 → 永远画(不看队友开关)
    • 图例里的计数是"他在这张图上有几个任务有位置",不是点数
    • 左侧任务面板也能看出来:行上有 我 / 队友昵称角标,展开明细第一行写「谁勾选」, 顶部还有 队友勾选 筛选(详见「任务侧边栏怎么用」)
  • 圆形小地图雷达同样会画队友勾选的任务(合并规则一样)
  • 同一张图开新局时,队友的残留位置会被清掉:新一局开始那一刻,本机先清掉"进局之前收到"的队友点, 同时通过服务端的 newraid → peer-reset 让队友那边也不再显示我的旧点
  • 共享内容跟着"谁在线"走:队友退出房间(或断线)后,他共享的标注与勾选任务立刻从图上/图例里消失 —— 不会再出现"人走了、右边没他的图例、笔画却还挂在图上"。服务端保留他的标注(这是有意的), 所以他一回来(重新加入房间)同一份数据立刻又能看到,不用他重画、也不受"只补发当前这张图"的限制; 本机自己画的那份始终走本地标注文件,退出房间、离线都不受影响。 (位置是"上一局最后一次按截图键"的快照,不清就会在新局的图上停一个假点)。 旧版服务端会忽略 newraid(本地清除仍生效,远端不生效)——想拿完整效果把 server/ 一起更新
  • 圆形小地图雷达同样会画队友;队友跑出雷达显示半径时,会按他所在的方位贴到圆边上 (图标缩小 + 虚线边框 + 一个朝外的小箭头,一眼看出"人在这个方向的外面",鼠标悬停能看到距离多少米)

设计取舍

  • 人人平等:没有房主、没有管理、没有踢人;唯一的约束是只能删自己的标注(服务端按身份校验), 这一条是防手滑/防误删,不是权限体系
  • 服务端极轻:单进程、纯内存(PERSIST=1 才落盘到 /data),运行时只依赖 ws, 空载 40–80MB 内存;房间空了 10 分钟自动回收
  • 房间里的人默认最多 16 人(MAX_ROOM_PEERS 可调),位置消息服务端限速 200ms 一条
  • 公网建议套反代上 wss://(客户端填 https:///wss:// 会自动加密);详见 server/README.md
  • 状态提示行只说真话:「加入房间」旁边那行字(正在加入… / 已加入房间 / 连不上服务端,正在自动重试…) 每次都由房间的真实状态重算。配置没改时再点一次「加入房间」主进程会直接 no-op(不想白折腾一条连接), 这时提示行会立刻回到"已加入房间",不会挂着过时的"正在加入…"误导你(探活结果这类临时话术也只是短暂停留)。
  • 握手有超时:TCP 连上了、hello 也发了,但服务端 8 秒内不回 welcome(进程假死/端口后面不是本服务), 客户端会主动掐掉重连,而不是让界面一直停在"正在加入…"

验收

npm run test:all                       # 客户端 224 项 + 服务端 47 项
node tools/verify-room.js              # 界面验收 66 项:进房(勾「启用房间」/点「加入房间」两条路)/队友标记与箭头/轨迹/图例分组/按人开关/点标记跳转/
                                       # 雷达上也有队友 + 出范围贴边方位指示/队友换图后旧点消失/我的标注同步(含离线补发)/删除同步
                                       # + 状态提示行不说假话(重复点"加入房间"不会卡在"正在加入…")+ 收尾还原用户配置
node tools/verify-room-2clients.js     # 真·多客户端:自起服务端 + 两个真客户端 + 截图->定位->房间->对方地图真链路,
                                       # 含"队友换图后旧点消失/图例改口/回来又出现"(21 项)
node tools/verify-room-live.js --url=wss://你的域名 --port=443 --room=联机自检 --clients=3
                                       # 连你自己部署的服务端做一次真·多客户端自检:N 个真客户端各自独立配置目录,
                                       # 走"往截图目录扔带坐标的截图 -> 自动定位 -> 同步"这条真链路,
                                       # 逐项断言定位/朝向/轨迹/图例/按人开关/雷达,并把大图与雷达截图存到 test-artifacts/
node tools/verify-server-image.js      # 不用 Docker 也能验镜像内容(文件集 / npm ci / HEALTHCHECK / 真客户端进房)
npm run dist:server                    # 服务端 Windows 单文件 exe(Node SEA)-> dist-server\...exe(自带启动自检)
node tools/verify-server-exe.js        # 服务端 exe 端到端验收(13 项:--version/--help/真起实例/healthz/
                                       # 两个真客户端进房/位置轨迹/椭圆标注/newraid 清残留/离开/关进程无残留)
node tools/verify-asar.js dist\win-unpacked\resources\app.asar   # 打包产物里到底有没有这个版本的代码

打包 Windows 一键运行 exe

npm run dist         # 客户端:electron-builder portable -> dist\塔科夫地图-<version>.exe
npm run dist:server  # 服务端:Node SEA 单文件    -> dist-server\tarkov-offline-map-server-<version>-win-x64.exe
  • 产物为 免安装单文件 exe(v1.2.0 起约 145MB,含 73MB 赛季文件参考截图),双击即用,自带图标与版本信息
  • 服务端那条 npm run dist:server 走的是 Node 官方的 SEA(把 server/server.js + ws 打进 blob 再注入 node.exe), 产物约 82MB,双击即启动,命令行开关见 server/README.md(--port/--persist/--data-dir/--help); 它是未签名的(postject 注入会丢掉 node.exe 的签名),首次运行 SmartScreen 会提示"未知发布者"
  • 若构建报 winCodeSign ... Cannot create symbolic link(Windows 未开启开发者模式/未提权), 可手工填充缓存后重试:
    $c = "$env:LOCALAPPDATA\electron-builder\Cache\winCodeSign"
    & node_modules\7zip-bin\win\x64\7za.exe x (Get-ChildItem $c -Filter *.7z | Select -First 1).FullName "-o$c\winCodeSign-2.6.0" '-x!darwin' -y
    或临时在 package.json 的 build.win 中加 "signAndEditExecutable": false(内层 exe 将不带图标/版本信息) (GitHub Actions 的 windows-latest 有权限创建符号链接,CI 上不会遇到这个问题)

持续集成 / 自动发布

.github/workflows/build.yml(客户端):

事件 行为
push 到 main / PR 装依赖 → 单测 → 离线管线模拟 → 构建 portable exe → 作为 Actions artifact 上传(保留 30 天)
push tag v* 同上,并自动创建 GitHub Release,上传 exe 与 SHA256SUMS.txt
手动 workflow_dispatch 可填版本号(临时写入 package.json 参与构建),构建并发布 Release

.github/workflows/server.yml(服务端,两条交付路径):

job 行为
test 服务端单测 + 集成测试(含命令行参数、newraid → peer-reset)
win-exe Windows 单文件 exe(Node SEA)→ 构建 + 自带启动自检 + tools/verify-server-exe.js 端到端验收 → Actions artifact;推 tag 时把 exe 挂到同一个 Release(tarkov-offline-map-server-<版本>-win-x64.exe + SHA256SUMS-server.txt)
image 构建并推 ghcr.io/neppure/tarkov-offline-map-server(main → :latest/:sha-xxx;tag → :X.Y.Z)

发布本地新版本:

npm version 1.2.1 --no-git-tag-version   # 改版本号(可省略,手工触发时也能填)
git commit -am "chore: v1.2.1"
git tag v1.2.1 && git push origin main --tags

验证

npm run verify           # 一键 UI 验收:环境自检 -> 逐套件跑 -> 汇总 + test-artifacts/verify-report.json
                         # (attach 套件由 runner 自己起隔离实例;受限宿主自动逐级让步并记进报告)
npm run test:all         # 客户端 224 项 + 服务端 47 项
npm test                 # 客户端单测(解析器/投影/映射 + 赛季数据 + 地图几何/地名文字/拖动平移 + 日志监听 + 任务数据 +
                         # 标注清洗与命中判定(含椭圆/Shift 正圆几何)+ 转移点文字 + 关于页 +
                         # 房间连接层/探活/身份保持/地址归一化/换图清点/新局清队友残留/入站数据防御与模糊测试 +
                         # 握手超时看门狗 + 成员显示 + 三组队友图例 + 状态提示行 + 雷达贴边钳位 + 雷达标注三档 +
                         # 定时自动截图(键名映射/间隔夹取/跳过与暂停/助手命令协议)+ 主窗口布局硬约束
                         # (左右浮窗挂在 #workarea 下、永远贴在顶栏下沿,不会再压住标注工具条)
                         # + 标注工具条接线(常驻顶栏 /「取消」退出 / 没有多余提示行)
                         # + 顶栏「固定地图方向」按钮(默认选中、反相逻辑、落盘、切换后立刻重画)
                         # + 滚动条美化(细/圆角/悬停变亮,别用原生那种又宽又亮的)
                         # + 人工补录点位 overlay(合并生效/幂等/上游补齐后自动跳过/文件缺失不影响加载)
                         # + 定位精度回归(解析不丢小数 / 投影往返 <1e-9m / 1cm 不量化 / 各图比例尺自洽 /
                         #   朝向不被整数化——防止以后有人手一抖加取整)
                         # + 雷达与主地图一致(勾选的任务点也画在雷达上 / 同一份勾选与透明度 /
                         #   地图中文名字典 / 表层标记开关)与"雷达上的字不会整体消失"回归
                         #   (上限裁剪与标名按"重要度 + 离圆心距离"挑,绝不整类丢、绝不清空)
                         # + 设置页目录按钮(日志/截图目录的「选择文件夹…」「打开文件夹」接线与
                         #   只选目录的 IPC)
                         # + 战局提示音(解析真实日志行 / 状态机三个时刻各响一次 / 倒计时落在最后几秒 /
                         #   历史回放不响 / 提前进图补一声;并断言"定位与换图不再有提示音")
                         # + 「进图要带」清单(钥匙按"或"分组、只收放置/使用类物品、去重、脏数据不抛;
                         #   真实任务数据里 ≥40 个任务能挑出钥匙)+ 黄色高亮接线
                         # + 队友共享勾选任务(协议清洗/去重/限量、能力协商 caps、整份覆盖发送、
                         #   人走了清他的勾选、指纹顺序无关、合并显示与「XX勾选的任务」图例接线)
                         # + 主窗口「图钉化(置顶)」已删除的回归(按钮/接线/IPC/preload 四处都不许回来)
                         # + 任务面板的队友勾选(新 chip 与交集语义 / 我·队友角标 / 展开写具体是谁 / 统计行)
                         # + 更新日志生成器(约定式提交的解析与分类 / 正文要点整理与上限 / 分节与完整提交列表 /
                         #   破坏性变更标记 / 真仓库冒烟:v2.1.0..v2.2.0 真提交能生成出来)
                         # + 设置页即时生效(每个 #set-* 控件都必须在 LIVE_FIELDS 里 / 取值与夹取规则 /
                         #   滑块实时·文本框失焦 / 没有保存取消按钮 / 雷达窗口大小接线)
                         # + 雷达新定位重新居中(位置真的变了才归零偏移 / 关掉自动居中就不许抢视野 /
                         #   窗口大小与显示半径变化后重新铺满圆盘 / 尺寸夹取与"以圆心为基准改大小"
                         #   + 拖窗口改大小后底图 viewBox/世界变换/覆盖层按新尺寸重算)),224 个用例
npm run test:server      # 房间服务端:命令行参数 8 项 + 协议纯函数 8 项 + 勾选任务转发 2 项 +
                         # 真起服务的集成测试 14 项(含 newraid -> peer-reset)+ 守卫行为 8 项 +
                         # 模糊测试 2 项 + Dockerfile/compose 一致性 5 项
node tools/preflight.js                 # 发布前闸门:工作区/版本三处一致/tag 是否已存在/测试/打包产物是否过期/asar 内容
                                        # (加 --with-image 还会验一次服务端镜像内容;全绿才会打印推送命令)
node tools/release-notes.js --version 2.4.1   # 把 CHANGELOG 里这一版拼进 Release 正文(CI 发布时自动做,见 build.yml;
                                              # 补历史 Release:gh release view v2.4.1 --json body -q .body > body.md
                                              # -> node tools/release-notes.js --version 2.4.1 --body body.md --out body.md
                                              # -> gh release edit v2.4.1 --notes-file body.md)
node tools/verify-server-image.js       # 不用 Docker 也能验镜像内容:照 Dockerfile 复刻文件集 -> npm ci --omit=dev ->
                                        # 起服务 -> 跑 HEALTHCHECK 原命令(含"端口没人时必须报故障")-> 真客户端进房画一笔
npm run simulate         # 用 samples 里的日志+截图跑完整管线
node tools/diagnose.js   # 诊断真实游戏日志:会话选择/文件匹配/事件解析
npm run visual-test      # 真实输入事件自检:滚轮缩放/拖拽/测距/标记图钉开关/赛季文件/小地图拖动与焦点,截屏到 test-artifacts/
powershell -File tools/verify-exe.ps1      # 打包版验收:启动 exe -> 截屏 -> 读状态 -> 关主窗口确认零残留
node tools/verify-exe-cdp.js               # 打包版深检(需 exe 带 --remote-debugging-port=9222 启动)
node tools/verify-about.js                 # 关于页面验收(15 项:标题改名/纯本地徽标移除/版本号/GitHub 地址/设置入口)
node tools/verify-room.js                  # 房间联机界面验收(66 项:脚本自起真服务端 + 一个真队友客户端 + 假队友脚本;
                                           # 含三组队友图例按人按类开关、队友开新局后旧点消失、离线标注补发、收尾还原)
node tools/verify-room-live.js             # 连真实服务端的多客户端自检(见上面「房间联机」一节;**--url 必填**,
                                           # 脚本里没有任何默认地址 —— 公开仓库里不许写死真实服务器地址)
node tools/verify-room-2clients.js         # 真·多客户端联机验收(28 项:自起服务端 + 两个真客户端,含截图->定位->房间->对方地图真链路 + 离场队友的共享标注/勾选一起下线、回来再现)
node tools/verify-raid-reset.js            # 新一局清场验收(11 项:假日志+假截图走完整管线,验玩家点/轨迹被清、旧进图行不误清)
node tools/verify-annotations.js           # 手动标注验收(21 项:常驻工具条/六种工具落笔/椭圆对角拖拽/Shift 正圆/橡皮/撤销/图例开关/换图不串味/重载后仍在/
                                           # 再点工具或 Esc 退出;标注文件先落盘备份,被强杀也能下次自动还原)
node tools/verify-mini-anno.js             # 雷达显示标注验收(8 项:默认"我的+队友的" / 三档切换 / 与图例开关联动)
node tools/verify-mini-quest.js            # 雷达与主地图一致验收(10 项:勾选的任务点在雷达上也画出来、两边 questItems 一致、
                                           # 关掉「任务区域」两个窗口一起隐藏、30 个撤离点同时在场也标出最近的 6 个 —— CDP 只读 DOM,不动系统鼠标)
node tools/verify-raid-alerts.js           # 战局提示音验收(11 项,**自己起隔离客户端 + 往假日志里追加真实格式的日志行**:
                                           # 开始匹配/匹配到了/倒计时最后几秒各响一次、截图定位与换图不响、
                                           # 倒计时落点(GameSpawned 后 8~11 秒)、提前进图补一声、app.log 有 [alert] 行)
node tools/verify-quest-share.js           # 队友共享勾选任务 +「进图要带」验收(24 项,**自己起隔离客户端 + 真服务端 + 假队友**:
                                           # 勾选共享出去/收进来、同一任务两人都勾只画一次(合并)、我·队友角标、
                                           # 「谁勾选」明细、队友勾选筛选与交集语义、图例「XX勾选的任务」开关只隐藏"只他勾"的、
                                           # 进图要带黄色高亮与钥匙)
node tools/verify-autoshot.js              # 定时自动截图验收(15 项;**必须用 TAKOV_AUTOSHOT_DRY=1 或 --autoshot-dry 启动客户端**,
                                           # 干跑模式只记状态不发按键:间隔节流/连续无效自动暂停/键名归一化/间隔夹取)
node tools/verify-mini-input.js            # 系统级真实鼠标输入验收:小地图拖动跟随 + 工具条按钮可点 + 位置记忆
node tools/verify-mini-pan.js              # 雷达 Ctrl+拖动平移地图验收(CDP 合成输入,不动系统鼠标,游戏在前台也能跑)
node tools/verify-settings-live.js         # 设置页即时生效 + 雷达窗口大小 + 新定位重新居中 + 主窗口改大小验收(35 项,**自己起隔离实例**:
                                           # 没有保存/取消、滑块只派发 input 就写进配置、窄视口收成一列不横向溢出、
                                           # 拖大小 -> 窗口与圆盘跟着变且圆心不动、定位回圆心、平移偏移留着、
                                           # 再定位归零回圆心、关掉自动居中就一格不动、拖显示半径立刻生效、
                                           # 改窗口大小后底图 viewBox/世界变换/玩家标记/图例四者仍然对齐;
                                           # CDP + 往临时截图目录丢假截图,不碰系统光标、不注入键鼠)
node tools/verify-legend-text.js           # 图例大类「只看图标不要文字」验收(21 项:每个大类的 Aa 开关 / 置灰说明、
                                           # 关掉某类文字后该类 <text> 变 0 而图标一个不少、markerToggles 不受影响、
                                           # 点显隐勾选框不会连带点 Aa、全开全关不动文字开关、雷达同步跟着变;
                                           # 需先起客户端,或用 npm run verify -- --only=legend-text)
node tools/verify-quests.js                # 任务侧边栏验收(41 项:搜索/分组/勾选/图层/图例覆盖/详情卡 + "位置在别的图"提示与一键切图,CDP 合成点击,不动系统鼠标)
node tools/scan-privacy.js                 # 开源前扫描样例里的账号ID/邮箱/token

tools/verify-mini-input.js 用 SetCursorPos + mouse_event(真实输入,不是合成事件)验收小地图, 检测到游戏在前台时会自动跳过,避免把点击送进游戏。 tools/verify-mini-pan.js 只用 CDP 合成带 Ctrl 修饰键的鼠标事件(不碰系统光标),随时可跑。

本轮新增功能(战局提示音 / 共享勾选任务 / 进图要带 / 任务面板队友勾选)的验证状态: 单测/集成测试之外,三项都写了自起隔离实例的端到端验收并且已经跑绿: node tools/verify-raid-alerts.js(11/11)、node tools/verify-quest-share.js(24/24)、 node tools/verify-mini-quest.js(10/10,需先 --remote-debugging-port 起客户端)。 回归也跑过:verify-quests.js 41/41、verify-room.js 63/63(含新增的"离场队友的共享标注/勾选一起下线" 与"离开房间后队友笔画消失"断言)、verify-raster.js 28/28、 verify-mini-anno.js 8/8、verify-raid-reset.js 11/11、verify-about.js 15/15、 verify-autoshot.js 15/15(干跑)、npm run visual-test(renderer errors: NONE)。 这两次验收抓出了三个真问题,都已修:给窗口重载兜底的 raidAlert 曾经"粘"在状态里(后续每条推送都重带一遍)、 图例里「XX勾选的任务」的计数没跟着"只被他勾"的开关变化、以及写验收脚本时踩到的 "渲染层还没注册 onState 就 selectMap → 广播被丢掉"(脚本里已加"渲染层就绪"闸门)。

更新日志 / 版本说明

每个版本都打 tag(v2.2.0)并发布 Release,逐版说明见 CHANGELOG.md。 它是按提交记录手工整理的(提交正文里写清了"改了什么、为什么、怎么验"),要草拟下一版说明:

npm run changelog                                # 上一个 tag..HEAD,打到屏幕
npm run changelog -- --from v2.1.0 --out /tmp/next.md   # 指定区间 + 落盘

tools/make-changelog.js 会按 type(scope): 标题 分节(新功能 / 修复与性能 / 重构 / 文档 / 测试 / 构建与 CI),把提交正文里的 - 要点 整理成子项,并附上"完整提交"列表与对比链接。

数据更新(游戏大版本更新后)

npm i socket.io-client           # 首次
npm run fetch:data               # 重新拉取地图配置与 SVG(默认站台版本见 tools/fetch-all.js)
                                 # 注意:抓取只覆盖 data/maps-dump.json,人工补录在 data/manual-extracts.json 里不受影响
npm run fetch:tiles              # 重新下载无 SVG 地图的瓦片底图(实验室/迷宫/破冰船)
npm run fetch:quests             # 重新拉取任务/目标/区域坐标 + 中文名(写入 data/quests-dump.json,约 560KB)
npm run fetch:season             # 重新拉取赛季文件刷点 + 类型图标
npm run fetch:season:images      # 下载赛季文件位置参考截图原图(约 73MB)
npm run fetch:icons              # 补齐标记图标
node tools/check-svg-pack.js     # 对比上游素材包,确认底图是否真的变了
node tools/diff-dump.js          # 与旧快照逐点 diff(撤离点/危险区/BTR 等)
# 站台当前版本(比对 tools/fetch-all.js 里的 VERSION)
curl -s https://member.kaedeori.com/ | grep -o 'static/[0-9.]*' | head -1
# 素材包清单(每份快照的 sha256,换了就知道)
curl -s https://cdn.kaedeori.com/uploads/tarkov/interactive-map/<版本>/manifest.json
# tarkov.dev 镜像(点位主源;注意别设 user-agent)
curl -s -o build/tarkovdev-pve-maps.json https://json.tarkov.dev/pve/maps

数据源清单(按数据类型,2026-09 实测)

数据类型 主源 备源 / 兜底 怎么检测它更新了
点位(撤离点/转移点/Boss/出生点/钥匙/开关/危险区/物资/BTR) tarkov.dev JSON 镜像 https://json.tarkov.dev/{pve|regular|season}/maps(一次 8.2MB,字段与我们所用完全对应,含 transferItem、新转移点、修正过的坐标) https://api.tarkov.dev/graphql(支持 lang: zh,但 2026-09 实测常报 GraphQL server unavailable);补漏用 Tarkov Market / wiki(见下) 按 ID 逐图 diff(用 node tools/check-upstream.js,或自己拉镜像比 extracts/transits/... 的 ID 集合与坐标)
点位中文名 kaedeori 站台(lang: zh) GraphQL lang: zh 站台静态版本号变化
底图 SVG kaedeori 素材包 interactive-map/<版本>/assets/maps/*.svg 官方仓库 the-hideout/tarkov-dev-svg-maps(每张图单独文件、有提交历史,可精确定位哪张重画了) manifest.json 的 sha256 一比即可;官方仓库看单文件 commit
瓦片底图(实验室/迷宫/破冰船) kaedeori CDN(固定 z=3,每层 8×8) — npm run fetch:tiles 前后比对文件数/大小
任务 + 目标坐标 + 中文 json.tarkov.dev/{mode}/tasks + tasks_zh 同源 GraphQL npm run fetch:quests 后看任务数变化
赛季文件刷点 kaedeori 站台(上游无等价数据) — npm run fetch:season
物品/价格/弹药/防具/钥匙 tarkov.dev JSON 镜像 https://json.tarkov.dev/{regular|pve}/items + items_zh(一次 16.4MB,5442 件,两种模式各一份) — npm run fetch:upstream 后 npm run fetch:economy,看物品数/有价数
商人交换/藏身处制作/藏身处模块 json.tarkov.dev/{mode}/{barters,crafts,hideout} — npm run fetch:market 后看条数(1710/428/26)
物品图标 https://assets.tarkov.dev/<id>-icon.webp(64px,5442+5442 张,约 30MB) — npm run fetch:item-icons
BOSS 刷新率 kaedeori 站台 /api/tarkov/boss/list?gameMode=(与 tarkov.dev 同源,含每图刷新概率) — npm run fetch:bosses
任务描述/攻略/截图 逃离塔科夫中文Wiki https://www.eftarkov.com/task/<id>(546 个任务页 + 1472 张攻略截图) 英文 fandom(次链接) npm run fetch:guides 后 npm run fetch:shots
BTR 路线/站点/时刻 同一 Wiki 的 /btr 内联 JSON(3 张图、22 站、12 条路线,x/y 就是 SVG 像素坐标) — npm run fetch:btr
任务物品需求(收集清单) kaedeori /api/tarkov/task/requirements?gameMode=pvp|pve(注意没有 regular,pvp 即常规服) — npm run fetch:requirements
赛季特质 同一 Wiki 的 /Traits(34 条,页面里 window.TARKOV_TRAITS 只有 id,字段在 data-* 上) — npm run fetch:traits
图标 kaedeori CDN(map-icons/、assets/tarkov/images/) tarkov-dev 仓库 public/maps/interactive/*.png npm run fetch:icons
BTR 站点/线路 站台快照 btrStops(灯塔/森林源自 TarkovBTR 手工数据) tarkovbtr.com(纯前端、无公开接口,数据在 JS bundle 里) 站台数据变化
官方改动说明(语义对照) escapefromtarkov.com/news(如 1.1.5.0 灯塔重做) 17173/官方论坛中文转载 手动,补丁日看一眼

访问姿势(实测踩过的坑):json.tarkov.dev 前面挂着 Cloudflare—— 用 默认 fetch 头(不设 user-agent、不加 accept: application/json)稳定 200; 伪装浏览器 UA 反而会超时/403。单个文件要留 60s+ 超时,HEAD 请求一律 403(别用 HEAD 探测)。 另外 Electron 里加载外部站点时不要带 HTTP_PROXY(会 ERR_CONNECTION_CLOSED)。

可靠性分级:

  • 可自动、可复现:tarkov.dev 镜像、官方 SVG 仓库、站台素材包 manifest / socket 接口
  • 需要人工确认:Tarkov Market(撤离点最全,但坐标要挂浏览器钩子才拿得到)、wiki、官方新闻

推荐分工:点位以 tarkov.dev 镜像为准(比站台新、字段全),中文名/底图/瓦片/赛季继续用站台, 两边都缺的点位走 data/manual-extracts.json 人工补录(带来源标注)。点位的 ID 两边一致 (如灯塔 cc16b27f…=装甲列车),所以"镜像取字段 + 站台取中文名"可以按 ID 合并。

已知上游状态(2026-09-14 站台 / 2026-09-22 tarkov.dev 核查)

  • 站台静态版本 4.10.7 → 4.11.0(互动地图素材包 interactive-map/2026-09-13.1); 但 4.11.0 的地图数据与 4.10.7 逐图零差异(15 张图、所有点位字段都比过),版本号不等于数据更新
  • 底图:官方 Lighthouse.svg 最后更新 2024-01-30,尚未重画 1.1.5.0 灯塔重做后的地形
  • tarkov.dev 相对我们快照确实更新过:灯塔新增转移点 id=51(→破冰船,气垫船,需 Sudak-tudak 维修包)、 山间小路/湖边小径坐标修正(60m/80m)、湖边小径补 transferItem(Minefield map)、 储备站 +1(装甲列车)、实验室 −1(医疗区电梯)、新增两张图(ground-zero-tutorial、the-lab-dark)
  • 两家上游都缺:灯塔 5 条撤离点(含载具撤离点)——见下一节
  • 赛季文件刷点:419 个(赛季 1),覆盖除码头外 14 张图;码头 无刷点

人工补录点位(上游缺漏)

上游(kaedeori 站台,与 tarkov.dev 同源)的撤离点表本身有缺漏。灯塔实测确认游戏内有 通往军事基地的路(载具撤离点)(付费载具撤离,单次、约 5000 卢布/人),但两家上游都没有, 连带着还缺 南部大路(PMC)、隧道(合作撤离点)、厂区大门(Scav)、浮动码头下方的藏身处(Scav)。

补录写在 data/manual-extracts.json,由 src/maps-data.js 的 applyOverlay() 在加载时合并: 主进程走一遍,app://data/maps-dump.json(渲染层是直接 fetch 这个文件的)也走一遍。 这样 npm run fetch:data 重新抓取不会把补录冲掉;上游将来自己补齐同 id 时会被自动跳过。

坐标来源:tarkov-market 的标记点坐标与我们的坐标系差了轴交换 + 约 4° 旋转, 用两边都有的 108 个标记做 ICP 对齐(66 个内点、RMS 3.7m)后换算,再逐点放大对着底图核对 (载具撤离点落在通往储备站那条路上、藏身处落在浮动码头上)。条目里带 sourceName/sourceUrl/note 便于追溯。

node tools/check-upstream.js 会把人工补录单独列出来(+人工补录),不计入"上游差异"。

目录说明补充

samples/screenshots/*.png 是占位图(内容无关紧要,管线只解析文件名里的坐标与四元数), 避免把个人游戏截图放进公开仓库。真实日志样本中的账号标识已替换为占位值。

任务相关的文件:

  • tools/fetch-quests.js 构建期快照脚本(跑一次生成下面的 JSON,之后运行时完全不联网)
  • data/quests-dump.json 任务快照(中文名 + 目标 + 区域轮廓 + 物品刷新点 + 物品/钥匙中文名,约 880KB)
  • src/quests-data.js 主进程侧加载与统计
  • renderer/common/quest-filter.js 搜索 / 筛选 / 商人-阶段分组(纯函数,test/quests.test.js 覆盖)
  • renderer/map.js 里的"任务侧边栏"段:面板渲染 + 勾选持久化 + 与地图图层联动

手动标注相关:

  • src/annotations.js 标注存储(清洗 + 读写,test/annotations.test.js 覆盖)
  • %APPDATA%\tarkov-offline-map\annotations.json 标注数据(按地图 id 分开存,世界坐标)
  • renderer/common/map-view.js 的"手动标注"段:绘制/橡皮/撤销/命中判定 + 椭圆几何;renderer/map.js 的"手动标注"段负责常驻工具条与持久化

定时自动截图(定时刷新定位)相关:

  • src/auto-shot.js 决策 + 按键助手(纯 Node,test/auto-shot.test.js 覆盖;Windows 上用常驻 PowerShell 发一次系统按键)
  • main.js 的"定时自动截图"段:把配置/局内状态喂给 runner,并按 5 秒节流把状态广播给界面
  • 只在局内(日志里出现过进图行)+ 游戏窗口在最前面时按;连续 3 次没拿到新坐标自动暂停
  • tools/verify-autoshot.js 用干跑模式验收(TAKOV_AUTOSHOT_DRY=1,只记状态不发按键)

免责声明

本项目仅读取玩家自己的游戏日志与截图文件,不注入进程、不读写游戏内存。 "定时自动截图"(默认关)是唯一会向外发送输入的功能:它通过 Windows 的系统 API (keybd_event)发一次你在设置里指定的按键,让游戏自己写出带坐标的截图 —— 不注入游戏进程、 不读写游戏内存,并且只在"局内 + 游戏窗口在最前面"时才发(连按 3 次无效会自动暂停)。 即便如此它仍然是"合成输入",请自行评估使用风险,建议只在离线/单人局使用。 默认不联网:只有你显式启用房间功能并填写服务器地址后,程序才会连接那一台服务器 (房间服务器收不到你的游戏数据,只收到"位置点 / 标注 / 昵称"这几样,详见房间功能一节)。 塔科夫官方禁止任何第三方辅助工具,仅供学习与离线/单人模式自用,风险自负。 地图数据来源:tarkov.dev / the-hideout 开源底图 + kaedeori 站点的公开只读数据快照; 物品、价格、弹药、防具、交换与制作配方来自 tarkov.dev 的公开数据快照; 任务描述、任务攻略与攻略截图来自「逃离塔科夫中文Wiki」 (本项目为开源非商业项目,已注明来源并逐任务回链,内容版权归原站与原作者所有;如权利人不同意收录请提 issue,我们会移除); BOSS 数据来自 kaedeori 站点的公开只读接口; 任务与任务区域坐标来自 tarkov.dev 的公开数据快照(json.tarkov.dev/regular/*); 游戏素材版权归 Battlestate Games 所有(详见 LICENSE)。

About

《逃离塔科夫》纯本地实时地图:日志自动识图 + 截图定位 + 悬浮小地图 + 赛季文件刷点,运行时不联网

Topics

Resources

Stars

7 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages