《逃离塔科夫》的第三方实时地图辅助工具:
监听游戏日志自动识别当前地图 + 监听截图目录自动定位玩家 + 悬浮小地图。
默认完全本地运行:程序本身不发网络请求、无遥测。v2.0 起提供可选的房间联机
(和队友互相看到位置与标注),需要你自己部署 server/ 里的服务端并填写地址,不填就一行网络代码都不会跑。
到 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
-
自动识图:塔科夫每次进局会在
文档\Escape from Tarkov\Logs\log_<时间>_<版本>\写入application_*.log。日志中的scene preset path:maps/<bundle>_preset.bundle(进图加载)Location: <raidCode>(NetworkGameCreate,进局时刻) 即可确定 raidCode → 地图。监听器持续追加读取最新会话日志,自动切换地图。
-
截图定位:游戏中按
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 站点、赛季文件刷点、地名…),与"高级设置"(定位自动缩放/居中、
表层显示全部标记、自动切换图层、声音提示(只用于战局:匹配/匹配到了/进图倒计时,可调"最后几秒")、自动删除截图文件、小地图雷达参数等)均持久化到本地设置文件。
设置页改动即时生效(没有「保存 / 取消」按钮):拖滑块、勾开关当场就变并自动记住;
文本框(目录 / 服务器地址 / 截图键)在回车或点到别处时写入 —— 免得每敲一个字就重启一次日志监听。
设置里的游戏日志目录 / 截图目录除了手输路径,还能点「选择文件夹…」用系统文件夹选择框挑
(选完立刻生效),旁边的「打开文件夹」直接在资源管理器里打开当前路径。
-
赛季文件刷点(版本活动找东西):每个赛季有 8 类"赛季文件"(PMC 人员档案 / 医疗 / 财务 / 员工 / 技术 / 蓝图 / 测试 / 项目文件)在各图固定刷点,社区提交 + 官方审核后公开。 快照工具按地图抓取已审核通过的刷点(含参考坐标与类型元数据),地图上以物品图标 + 中文名药丸 + 类型色圆底标出,图例里按文件类型分别开关,点击标记给出中文说明与坐标。 每个刷点还附带社区提交的位置参考截图(419 张原图,webp,约 73MB):点标记后卡片内嵌缩略图, 再点一下弹出大图查看器(滚轮缩放 / 拖动平移 / 双击复位 / Esc 关闭),离线也能一眼看到文件长什么样、 在哪个角落。
-
坐标→像素(与原站投影数学一致):
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]
-
楼层判定:
z(高度) 落在各楼层layers[].extents[].height区间且位于该层区域矩形内 → 自动切层 (SVG 底图按data-layer分组:Ground_Level / First_Floor / Second_Floor / ...)。 -
底图有两种:
- 大多数图用上游的 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。
- 大多数图用上游的 SVG(
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 内)"判定双击 |
默认关闭:不填服务器地址,客户端一行网络代码都不会执行(离线优先是硬承诺)。 开了之后,同一个房间里的人能互相看到位置、朝向、轨迹和手动标注。
你的客户端 ─┐
队友的客户端 ┼── 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- 客户端顶栏 设置 → 房间(联机):填
服务器地址(内网 IP 或域名,例如192.168.1.10) 与房间号(你们商量的暗号,建议 6–8 位随机字符,口令可选)→ 点 测试连接(会显示服务端版本) → 点 加入房间。顶栏会出现在线 · N 人的小胶囊。 - 队友按同样的地址和房间号加入即可。
端口要放行: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 # 打包产物里到底有没有这个版本的代码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 未开启开发者模式/未提权), 可手工填充缓存后重试:或临时在 package.json 的$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
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 --tagsnpm 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/邮箱/tokentools/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| 数据类型 | 主源 | 备源 / 兜底 | 怎么检测它更新了 |
|---|---|---|---|
| 点位(撤离点/转移点/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 合并。
- 站台静态版本 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)。