迁移地图数据

问道把「在哪个世界画了什么」记在 config/howtogo/ 下,而目录名是由世界名或服务器地址 算出来的,不是你随手起的名字。所以一改世界名、一换服务器地址、一搬游戏实例, 数据不会自己跟过去——它没有丢,只是模组按新名字去找,没找到。 0.2.2 起这条规则变了一个地方:中文世界名不再变成一串下划线,而是转成拼音 (sp_新世界 → sp_xin_shi_jie);升级时旧目录会自己改名过去, 但降级回去会读不到。这一页讲目录名怎么算、哪些操作其实不用搬、要搬的时候按什么顺序做; 「改名之后路没了」的常见情况都能在这里找回。如果你只是想把一整个世界搬到另一台电脑或发给朋友, 0.2.2 也提供了用压缩包整份导出、导入的办法,见用压缩包搬家。 这里说的是问道自己的数据——路网、地点与公共交通线路; Xaero 世界地图自己的缓存不在 config/howtogo/ 里,也不该在这里搬。

一句话:名字决定目录,记录决定归属。要搬数据,先让新名字把目录建出来,再把旧目录里的 .json 复制进去——.world 标记留给游戏自己写。0.2.2 起中文名先转拼音; 想整份搬走,也可以直接用压缩包(见用压缩包搬家)。

数据在哪,目录名怎么来的

所有数据都在你这个游戏实例的 config/howtogo/ 下。官方启动器就是 .minecraft/config/howtogo/;用 PCL、HMCL 这类启动器时,是那个实例的「游戏目录」下的 config(开了版本隔离则在对应版本目录里),不是启动器自己的安装目录。 别去存档的 saves 目录里找:联机时客户端读不到服务器存档,所以问道从一开始就把数据放在 config 里,而不是存档旁边。

config/howtogo/ 下再按世界分目录。世界的标识由两样东西算出来: 单人存档用世界名(level.dat 里的 LevelName,就是选存档界面里 显示的那个名字),多人服务器用服务器地址(你填进服务器列表的那一串,不是它上面的显示名)。 算出来的 key 前面再加上 sp_ 或 mp_:

你在游戏里看到的 世界名(key) config/howtogo/ 下的目录
单人存档,世界名「新世界」 sp_新世界 sp_xin_shi_jie
单人存档,世界名「江南」 sp_江南 sp_jiang_nan
单人存档,世界名「My World」 sp_My World sp_My_World
服务器地址填 mc.example.net mp_mc.example.net mp_mc.example.net
服务器地址填 mc.example.net:25565 mp_mc.example.net:25565 mp_mc.example.net_25565

算目录名分两步。第一步把中文转成拼音:汉字逐字转写、去掉声调,音节之间留一个空格—— 新世界 变成 xin shi jie。第二步只保留 A-Z、a-z、 0-9、.、_、-,其余每个字符各换成一个下划线—— 拼音里的空格于是成了分隔用的下划线,sp_新世界 就成了 sp_xin_shi_jie。

纯 ASCII 的名字(英文世界名、服务器地址)不做拼音转写,原样进入第二步: 空格、冒号仍然换下划线。所以对 sp_My World → sp_My_World、 mp_mc.example.net:25565 → mp_mc.example.net_25565 这类名字, 结果和旧版本完全一样。这是 0.2.2 的破坏性变更: 以前中文世界名是纯按字符替换,有几个字就有几个下划线,sp_新世界 是 sp____; 现在换成拼音,既能一眼认出是哪个世界,也让「新世界」和「旧世界」不再指向同一个目录。 名字特别长时会截断到文件系统能接受的长度,剩下的靠短哈希区分。

每个世界目录里再按维度分文件。维度名不参与拼音转写,仍然是老规则: : 换成下划线,所以 minecraft:overworld 就是 minecraft_overworld。 这是故意的——如果让维度名也跟着转,冒号会被 ICU 改成「冒号加空格」, 文件名就变成了 minecraft__overworld.json,已有路网看起来就像「消失」了。 目录名是给人看的,文件名是模组找自己数据用的,两套规则各管一件事:

维度 id 文件名前缀
minecraft:overworld(主世界) minecraft_overworld
minecraft:the_nether(下界) minecraft_the_nether
minecraft:the_end(末地) minecraft_the_end
模组维度,例如 mymod:sky mymod_sky
文件 内容
<维度>.json 道路网络:节点、路段、道路名称、地点与地点类型。
<维度>-lines.json 公共交通线路:线路名、类型、按顺序的站点。
<维度>-rail-names.json 自动识别铁路的名称(按路段两端坐标记,所以能跟着铁路图层重建)。

每个世界目录里还有一个没有扩展名的 .world 文件,内容是「这个目录属于哪个世界」—— 写的是原始的世界 key(例如 sp_新世界、sp_My New World, 中文、空格、大小写都原样保留),不是目录名。0.2.1 起就有这个文件; 0.2.2 起它是目录归属的依据:模组先找记录对得上的目录,名字不对就把它改名到算出来的名字, 实在改不了才继续用旧名字——数据跟着记录走,不跟着名字走。

它同时负责区分撞车的名字:两个不同的世界名转写、清洗后相同(例如只差一个标点——A/B 与 A B 都是 A_B;或者长名字截断后前缀相同),后来者会得到 <目录名>-<短哈希>,不会读到别人的路。拼音让「江南」和「江北」这类 同字数的中文名不再撞车(sp_jiang_nan 与 sp_jiang_bei)。 0.2.2 之前留下的目录(0.2.1 的有记录、名字还是下划线;更早的没有记录、靠旧名字认领) 都会在第一次被打开时改名到拼音名,见下一节。

config/howtogo/ 根目录下还有几个与存档无关的文件: route_preferences.json(上次选的出行偏好与语音开关)、 map_filter.json(地图显示面板的开关与位置)、 mtr_line_marks.json(MTR 线路的逐条轨道标记)。它们不属于任何一个世界, 搬单个世界时不用动;完整清单见 配置与数据文件。 另外根目录下还有两个传输目录:exports/(我的导出)与 backups/(导入前的自动备份),见用压缩包搬家。

升级到 0.2.2:目录会自己改成拼音名

升级不需要做任何事。第一次打开某个世界时,问道按新规则算出拼音目录名,然后看两件事:

  • 已经有记录、且 .world 内容正是这个世界的目录:只要它的名字还是旧规则算的, 就整目录改名到拼音名,文件跟着走。0.2.1 留下的 sp____ 就是这样变成 sp_xin_shi_jie 的;名字已经对上的则原地不动。
  • 更早的、没有 .world 的目录:如果它的名字正好是旧规则算出来的 (中文全是下划线),它就是这个世界的老目录,同样整目录改名到拼音名,并补上记录。

两种情况都有兜底:拼音名已经被别的世界占用、或改名失败时,旧目录继续用, 只补一个 .world 记录——「一个世界不能因为目录名改不好就丢掉它的路」。 所以升级后如果看到目录名没变,不必手动改,它照常能读到。

风险在降级。用 0.2.2 存过档以后再退回 0.2.1,旧版本按老规则(中文全是下划线) 去找目录,找不到拼音名,那个世界的路网就是空的——文件还在,只是没人读。 要退版本,先在 0.2.2 里导出压缩包(见用压缩包搬家)或复制整个 config/howtogo/,再把 JSON 放进旧规则会读的目录。

哪些操作要搬,哪些不用

先分清一件事:问道认的是世界名,不是存档文件夹名。 世界名存在 level.dat 里,改文件夹不会改它。

操作 数据会怎样 要做什么
在 saves/ 里把存档文件夹改名(level.dat 不动) 世界名没变,目录也没变,照常读到 什么都不用做
改世界的显示名(level.dat 里的 LevelName;有些工具的重命名会连它一起改) 它会去找按新名字算出的目录(旧目录不会自动跟过去) 按下面「搬运步骤」搬
在服务器列表里改「服务器名称」 只是显示名,地址没变 不用搬
改服务器地址、域名、端口,或从 IP 换成域名 目录从 mp_旧地址 换成 mp_新地址 按下面「搬运步骤」搬
换电脑、换整合包、换游戏实例 数据还在旧实例的 config 里 复制整个 config/howtogo/
复制存档做备份,然后打开了副本 两个世界名相同,共用同一份数据 想让副本独立就先改名再搬
更新模组、删掉模组 jar 文件原样保留;升级到 0.2.2 时目录名会在第一次打开时改成拼音 不用搬(升级自动改名;降级见上一节)

两个世界名一字不差时,问道分不开它们,会共用同一个目录——这是它唯一 不打算区分的撞车。名字不同、但转写清洗后相同的(只差标点,或长名字截断到同一前缀) 由 .world 与短哈希处理,不需要你动手。所以「两个不同的存档共用了路」只可能是同名; 如果确实不同名却共用,那个目录大概是 0.2.2 之前留下、还没被新版本打开过(没有 .world 记录)。

搬运步骤:备份 → 先建新目录 → 只复制 JSON

下面这套顺序适用于所有人手搬运的场景(改世界名、换服务器地址、换电脑), 不要反过来做。单纯升级到 0.2.2 不用做这些——目录会自己改名:

  1. 备份。把整个 config/howtogo/ 复制一份到桌面或别的盘。 这里没有校验和、也没有自动备份,复制是唯一的后悔药。
  2. 完全退出游戏。修改会在停手约 3 秒后自动写盘,离开世界时还会再存一次; 游戏开着时替换文件,退出时可能被内存里的旧路网写回去。
  3. 用新名字进一次目标世界(或目标服务器)。这一步会让问道按新名字建好目录、 写好 .world。地图上会空无一物,这是正常的——它现在找的是新目录。
  4. 再退出游戏,打开 config/howtogo/。旧目录还在,新目录已经出现。
  5. 把旧目录里的 .json 复制到新目录。包括 <维度>.json、<维度>-lines.json、 <维度>-rail-names.json。不要复制 .world, 也不要动根目录那几个文件。
  6. 进游戏验证。地图上应该有路、地点与线路;可选 /howtogo webmap 再 /howtogo webmap status,状态行里的 sp_... / mp_... 就是现在认的世界;/howtogo selftest 的「世界数据」一项也会把路网读一遍。

只有同一维度的文件会互相覆盖:旧世界的主世界文件对上新世界的 minecraft_overworld.json,下界、末地同理;旧世界没有的维度不用管, 新目录里也就不会有那个文件。

场景一:世界改名

单人存档的目录由 sp_<世界名> 算出来。再强调一次:世界名是 level.dat 里的名字,不是 saves/ 下的文件夹名。 只改文件夹不用搬;改了世界名才需要。

  • 新名字是英文时,目录通常是 sp_NewName(空格换下划线)。
  • 新名字是中文时,目录是拼音:例如「新世界」→ sp_xin_shi_jie、 「江南」→ sp_jiang_nan。
  • 拼音名先到先得:如果新名字转写出来正好是另一个世界占着的目录名,问道会给新世界一个 <拼音名>-<短哈希> 目录,把数据搬到那个目录里。
  • 操作就是上一节的六步:进一次新世界 → 退出 → 把旧目录的 JSON 复制进新目录。
  • 反悔很容易:旧目录没有被删,把 JSON 复制回去、或者把世界名改回去即可。

场景二:服务器地址变了

多人目录是 mp_<服务器地址>,取的是你在「服务器地址」框里填的那串字符: 域名、IP、端口都算,大小写也算;: 会被换成下划线。例如填 mc.example.net:25565,目录是 mp_mc.example.net_25565。 服务器列表里那个「服务器名称」不参与目录名,改它没有影响。 服务器地址是纯 ASCII,0.2.2 的拼音规则不影响它——这里的规则和以前完全一样。

换地址(换域名、换端口、从 IP 换成域名、合租服换了入口)时,按通用步骤做: 用新地址进一次服务器让 mp_新地址 出现,退出,把 mp_旧地址 里的 JSON 复制进去。反过来也一样:把地址改回旧的那串,旧目录立刻又能读到。

如果两个地址下都已经有路(你在两个地址都玩过),问道没有合并功能: 同一维度只有一个 JSON,后复制的覆盖先复制的。先各自备份,再决定以哪份为准, 缺的那部分只能补画。

场景三:换电脑、换整合包、给朋友

数据是客户端本地的,不跟着存档走,也不跟着服务器走。换电脑、换整合包、 换游戏实例时,把整个 config/howtogo/ 复制到新实例的同一位置即可: 目录名、.world 都照原样过去,游戏目录的绝对路径变了也没关系—— 问道只认 config 下的相对结构。

只搬一个世界,也可以只复制对应的 sp_... / mp_... 目录: 世界名没变、.world 也对得上,放进去就能读。如果目标实例里已经有同名世界目录, 就按「搬运步骤」只复制 .json,别覆盖它的 .world。

想把客户端设置也带走,再加上 config/howtogo-client.toml。 route_preferences.json、map_filter.json、mtr_line_marks.json 都在 config/howtogo/ 里,会跟着整个目录一起走。

给朋友同理:打包 config/howtogo/ 发过去,解压到他游戏目录的 config/ 下。 最好两边用同一个模组版本;跨大版本搬之前先备份。真的读不回来时(例如文件被改坏), 道路文件会被改名为 .corrupt 放到一边,不会静默消失。

更省事的是用压缩包:在旧实例里导出 .zip 发给对方,他打开对应世界后导入即可 (见用压缩包搬家)——他不用关心目录名怎么算,也不用改任何文件名。

场景四:复制存档以后,两个世界共用一份路

把存档文件夹复制一份,两个世界的 LevelName 通常还是同一个, 所以问道看它们是同一个世界,读写同一个数据目录。在副本里画的路,原世界也看得见; 反过来也一样。这不是 bug,是「按世界名区分」这条规则直接推出来的结果。

想让副本拥有独立的数据,可以这样拆开:

  1. 退出游戏,先备份当前共用的那个数据目录。
  2. 给副本改一个世界名(改 level.dat 里的 LevelName;只改文件夹名没有用), 让两个世界的 key 不同——中文名会得到一个新的拼音目录。
  3. 打开改名后的副本一次,让它建立自己的新目录,然后退出。
  4. 把原目录里的 JSON 复制到副本的新目录。此后的修改就各记各的了。

用压缩包搬家

0.2.2 新增了「地图存档」界面:/howtogo data 打开它,一个按钮把当前世界的道路、地点、 铁路名称、公共交通线路与附属数据打成一个 .zip 放进 config/howtogo/exports/; 另一个按钮把别人的 .zip 导入回来。指令也能做同样的事:/howtogo export 直接导出, /howtogo import [压缩包] 读指定文件;压缩包也可以直接拖进那个界面。

它的好处是不用碰目录名:导出的是「这个世界的数据」,导入的是「你现在打开的世界」, 中间那套世界名 → 拼音目录名的算法完全不用管。换电脑、给朋友、整份备份都适用。

导出与导入各做了什么

  • 导出只打包当前世界目录里的数据文件,不碰 config/howtogo/ 根目录那几个偏好文件, 也不碰别的世界。
  • 导入无视压缩包名与内部目录名:目录层级被剥掉,包里的 .world 记录改写成当前世界, 数据写进当前世界的目录——所以收到别人发来的包,打开自己的世界导入就行。
  • 覆盖前有警告:写明写进哪个世界、来源与时间、文件数、旧数据会先备份。 确认后先备份到 config/howtogo/backups/,再整目录替换。
  • 是替换,不是合并:包里没有的维度文件会被删掉。两份数据都想留,得先各自备份、选定一份, 缺的部分重画。
  • 备份能一键回滚:自动备份的文件名带 -backup,在「可导入的压缩包」列表里单独标黄, 再导入它一次就回到导入之前。
  • 替换是一次目录改名:新数据先在旁边建好再改名到位;旧目录先改名成 <存档>.replaced-<时间>,删掉它的 .world 记录后再删除—— 万一删不掉,留下来的目录也不会冒充当前世界的数据。

它只接受认识的文件

导入时只读 .json:__MACOSX/、.DS_Store、.world、 *.part、*.corrupt 会被跳过;带 .. 或绝对路径的条目不跟随; 文件数与解压总大小有上限;没有任何可读数据的包会被直接拒绝,当前地图不动。 列表里的来源分三种:导入文件夹、我的导出、备份。 自检里也多了一项「地图存档压缩包」——它真的导出、导入一次并逐字节核对。

压缩包是整目录替换,适合「整份搬走 / 整份恢复」。如果你只想把主世界的几份 JSON 挪到另一个实例、又不想动那个世界原有的数据,仍然用上面的「搬运步骤」只复制 .json。

手工改目录名,与 .world 的坑

先记住一条:目录名不是自由命名的。它是按世界 key 算出来的(中文转拼音、其余非法字符换下划线), 而 0.2.2 起真正决定归属的是目录里的 .world 记录。 所以手工改名字通常不会丢数据——模组会按记录把目录找回来,并在下次打开时把它改回按名字算出的那个。 但没有好处,而且改名过程中如果目标名字已被占用,它会停在旧名字上,白折腾一趟。

0.2.2 的规则是「记录优先」:先找 .world 内容等于当前世界 key 的目录, 找到就用它(名字不对就改名);找不到记录,才按名字算、并按旧规则兜底认领。由此有三条:

  • 推荐:按「搬运步骤」来,让游戏自己建目录、自己写 .world,你只复制 .json。
  • 不要删 .world:删掉以后目录就「没有归属」了。它的名字如果正好是旧规则算出来的 (中文全是下划线),第一个打开的世界会认领它;如果它是拼音名,问道不会自动认领 (那可能是别的世界改名后留下的旧数据),宁可为当前世界另建一个带短哈希的目录—— 看起来就是「数据还在,但没了」。
  • 整个目录改名可以,但没必要:带记录的目录改名后能被找回来; 更稳的做法是别动它,想要一个好看的名字就在游戏里改世界名。

目录名后面带一段 -1a2b3c4d 这样的短哈希,不是坏了,是「这个名字已经被另一个世界认领了」。 短哈希由世界名算出来,同一个名字每次算出的后缀都一样,所以它不会天天变。 想知道哪个目录是游戏正在用的,看每个目录里的 .world:内容等于当前世界 key 的那一个才是。 用不到的哈希目录可以备份后删掉,但别在没确认之前删。

出错了怎么找回

改名后进游戏,路全没了——数据丢了吗?

通常没丢。新目录是空的,旧目录还完整地待在旁边。退出游戏,按「搬运步骤」把旧目录里的 .json 复制进新目录即可。注意先别在新世界继续画:复制旧文件会覆盖同名的道路文件, 如果已经画了新路,先把新文件备份出来再决定留哪份。

单纯升级到 0.2.2 不会遇到这种情况——旧目录会自动改名到拼音名; 这一条说的是你手工改了世界名、换了服务器地址之后。

为什么多了一个带短哈希后缀的目录?

名字撞车了:另一个世界已经占着不带哈希的那个目录名。0.2.2 里常见的是「转写清洗后相同」—— 两个名字只差一个标点(A/B 与 A B),或者长名字截断到同一前缀。 看两个目录里的 .world,把「属于当前世界」的那一个作为目标,数据搬进去。 旧的那份先留着,确认不需要再删。

我把整个文件夹复制过去了,为什么还是读不到?

多半是把旧的 .world 也一起复制了。它写着旧世界名,游戏因此认为这个目录属于别人, 转而新建了一个哈希目录。保留目标目录自己的 .world,只复制 .json; 拿不准的话,就按「搬运步骤」让游戏自己把目录建出来。

两个不同名字的世界,却共用同一份路?

先确认「不同名字」是不是只改了存档文件夹。文件夹名的不同不改变世界名;两个世界名完全一样时, 共用是预期的(见场景四)。转写清洗后相同的名字会各自得到短哈希目录,不会共用; 如果确实不同名却共用,那多半是 0.2.2 之前留下的旧目录还没被新版本打开过(没有 .world 记录), 升级后第一次打开时就会按记录分开。

数据能合并吗?

不能自动合并。同一维度只有一个 <维度>.json,两张路网没有「取并集」的入口。 如果两边都有想保留的路,先各自备份,选一份作底,再把缺的路重画一遍。 想让整份数据直接替换,可以用压缩包导入——但那是替换,不是合并(见用压缩包搬家)。

目录里出现了 .part 或 .corrupt 文件

.part 是保存中途留下的半成品,正常退出后一般不会留着; .corrupt 是道路文件读不回来时被改名放到一边的原文件,可能还能手工救回一部分。 两者都先别删,备份整份目录再排查。

几条规矩

  • 先备份。复制整个 config/howtogo/;想把设置一起带走,再加 config/howtogo-client.toml。只想整份搬走的话,导出压缩包更省事。
  • 关游戏再动文件。路网会在停手后自动写盘、离开世界时再存一次, 开着游戏替换文件可能被旧数据盖回去。
  • 复制 .json,不复制 .world;不要整个文件夹覆盖。
  • 0.2.2 起中文目录名是拼音。升级时旧目录会自动改名,不用管; 但用 0.2.2 存过档的别直接降级回 0.2.1——那边按老的下划线规则找目录,找不到。
  • 服务器地址要一字不差。大小写、端口、写 IP 还是写域名,都算不同的世界。
  • 数据只在客户端。服务器上没有你的路,换电脑不会自动同步,也不会从服务器下回来。
  • 删模组 jar 不会删数据。反过来说,删掉 config/howtogo/ 才会; 误删先看回收站和之前的备份。

相关阅读:文件清单、每一项配置与备份见 配置与数据文件; 改名后遇到「没有路线」之类的现象,见 常见问题与限制; 想确认当前世界名,可用 浏览器地图 的 /howtogo webmap status。