理论上是不爱玩游戏的,上一次研究 Wine 还是在五年前。但是不知道怎么回事,现在这些个垃圾游戏要花费我不少时间……为了减少切系统的次数,尝试使用 Wine 跑;分别维护她们是复杂的,又尝试用 sh 脚本实现自动化。这便催生了 youmu-thdemo 。之所以是个 demo ,一来其基础功能是从 zun 的页面下载 th06-th15 体验版并部署,二来尽管也能被用于启动正式版,我并没那么多正作的碟子来参考完善。

对 Wine 极其不熟悉,对 Windows 程序极其不了解……

任何一个现代版本的 Wine 都可以在默认配置下启动从红魔乡到紺珠传的整数作(其他没测捏),唯一令人不爽的是 custom.exe 的字体黑块块问题。在配置为默认中文环境的系统上应该不会出现这种问题(大概吧);而我的英文系统上, th07-th15 都可以正常自动枚举到可用的字体,唯独 th06 是黑方块乱码。

翻阅 WineHQ 官网求助区的一篇提问 How do I fix this font issue? 了解到,可以通过 WINEDEBUG=+font 环境变量来打印日志。那么大概思路就是从日志中寻找到程序需求的字体,再用 Wiki Font Replacement 章节所描述的方法替换。

综合起来 Wine 所需的环境变量就是下面这样↓。关于 WINEDLLOVERRIDES='mscoree,mshtml=' 的用途,我并不太清楚,只是它确实存在于一些相关的脚本中。

$ export WINEPREFIX="${WORK_DIR}/wine"
$ export WINEDLLOVERRIDES='mscoree,mshtml='
$ export WINEARCH='win32'
$ export WINEDEBUG=+font

fc-match 可以查看系统默认匹配的字体↓。

$ fc-match
NotoSans-Regular.ttf: "Noto Sans" "Regular"
$ fc-match :lang=zh-CN
NotoSansCJK-Regular.ttc: "Noto Sans CJK SC" "Regular"
$ fc-match :lang=ja
wqy-zenhei.ttc: "WenQuanYi Zen Hei" "Regular"

使用下面的命令记录日志↓。

$ LC_ALL=ja_JP.UTF-8 wine 'th06/custom.exe' &>th06-orig.log

然后就是翻日志。别试图看完它,它有十来万行。其实 Wine 是有在好好替换字体的,虽然主要是替换了标题栏的↓。

$ cat th06-orig.log |grep select_font\ Chosen
0090:trace:font:select_font Chosen: L"System Regular" (L"\\??\\Z:\\usr\\share\\wine\\fonts\\jvgasys.fon"/(nil):0)
0090:trace:font:select_font Chosen: L"WenQuanYi Zen Hei" (L"\\??\\Z:\\usr\\share\\fonts\\wenquanyi\\wqy-zenhei\\wqy-zenhei.ttc"/(nil):0)
0090:trace:font:select_font Chosen: L"WenQuanYi Zen Hei" (L"\\??\\Z:\\usr\\share\\fonts\\wenquanyi\\wqy-zenhei\\wqy-zenhei.ttc"/(nil):0)
0034:trace:font:select_font Chosen: L"System Regular" (L"\\??\\Z:\\usr\\share\\wine\\fonts\\jvgasys.fon"/(nil):0)
0034:trace:font:select_font Chosen: L"WenQuanYi Zen Hei" (L"\\??\\Z:\\usr\\share\\fonts\\wenquanyi\\wqy-zenhei\\wqy-zenhei.ttc"/(nil):0)
0034:trace:font:select_font Chosen: L"WenQuanYi Zen Hei" (L"\\??\\Z:\\usr\\share\\fonts\\wenquanyi\\wqy-zenhei\\wqy-zenhei.ttc"/(nil):0)
0024:trace:font:select_font Chosen: L"System Regular" (L"\\??\\Z:\\usr\\share\\wine\\fonts\\jvgasys.fon"/(nil):0)
0024:trace:font:select_font Chosen: L"WenQuanYi Zen Hei" (L"\\??\\Z:\\usr\\share\\fonts\\wenquanyi\\wqy-zenhei\\wqy-zenhei.ttc"/(nil):0)
0024:trace:font:select_font Chosen: L"WenQuanYi Zen Hei" (L"\\??\\Z:\\usr\\share\\fonts\\wenquanyi\\wqy-zenhei\\wqy-zenhei.ttc"/(nil):0)
0024:trace:font:select_font Chosen: L"System Regular" (L"\\??\\Z:\\usr\\share\\wine\\fonts\\jvgasys.fon"/(nil):0)

$ cat th07-orig.log |grep select_font\ Chosen
0090:trace:font:select_font Chosen: L"System Regular" (L"\\??\\Z:\\usr\\share\\wine\\fonts\\jvgasys.fon"/(nil):0)
0090:trace:font:select_font Chosen: L"WenQuanYi Zen Hei" (L"\\??\\Z:\\usr\\share\\fonts\\wenquanyi\\wqy-zenhei\\wqy-zenhei.ttc"/(nil):0)
0090:trace:font:select_font Chosen: L"WenQuanYi Zen Hei" (L"\\??\\Z:\\usr\\share\\fonts\\wenquanyi\\wqy-zenhei\\wqy-zenhei.ttc"/(nil):0)
0034:trace:font:select_font Chosen: L"System Regular" (L"\\??\\Z:\\usr\\share\\wine\\fonts\\jvgasys.fon"/(nil):0)
0034:trace:font:select_font Chosen: L"WenQuanYi Zen Hei" (L"\\??\\Z:\\usr\\share\\fonts\\wenquanyi\\wqy-zenhei\\wqy-zenhei.ttc"/(nil):0)
0034:trace:font:select_font Chosen: L"WenQuanYi Zen Hei" (L"\\??\\Z:\\usr\\share\\fonts\\wenquanyi\\wqy-zenhei\\wqy-zenhei.ttc"/(nil):0)
0024:trace:font:select_font Chosen: L"System Regular" (L"\\??\\Z:\\usr\\share\\wine\\fonts\\jvgasys.fon"/(nil):0)
0024:trace:font:select_font Chosen: L"WenQuanYi Zen Hei" (L"\\??\\Z:\\usr\\share\\fonts\\wenquanyi\\wqy-zenhei\\wqy-zenhei.ttc"/(nil):0)
0024:trace:font:select_font Chosen: L"WenQuanYi Zen Hei" (L"\\??\\Z:\\usr\\share\\fonts\\wenquanyi\\wqy-zenhei\\wqy-zenhei.ttc"/(nil):0)
0024:trace:font:select_font Chosen: L"WenQuanYi Zen Hei" (L"\\??\\Z:\\usr\\share\\fonts\\wenquanyi\\wqy-zenhei\\wqy-zenhei.ttc"/(nil):0)

找到这些 WenQuanyi Zen Hei 的部分,可以看到是这样的逻辑过程↓。

0024:trace:font:font_SelectFont L"\ff2d\ff33 \30b4\30b7\30c3\30af", h=-13, it=0, weight=400, PandF=00, charset=1 orient 0 escapement 0
0024:trace:font:font_SelectFont DC transform 1.000000 0.000000 0.000000 1.000000
0024:trace:font:find_best_matching_face (it=0, bd=0) is selected for (it=0, bd=0)
0024:trace:font:select_font Chosen: L"WenQuanYi Zen Hei" (L"\\??\\Z:\\usr\\share\\fonts\\wenquanyi\\wqy-zenhei\\wqy-zenhei.ttc"/(nil):0)

$ echo -e -n "\x2d\xff\x33\xff\x00\x20\xb4\x30\xb7\x30\xc3\x30\xaf\x30" | iconv -f UTF-16LE -t UTF-8
MS ゴシック%

事实证明 th07-th15 custom.exe 的界面都是使用了 MS ゴシック 字体, Wine 将其替换为了文泉驿正黑。如果在 HKEY_CURRENT_USER\Software\Wine\Fonts\Replacements 手动替换其为 Noto Sans CJK SC ,就可以看到 th07 的变化↓。 th06 的日志则毫无改变。

$ cat th07-gothic.log |grep select_font\ Chosen
0090:trace:font:select_font Chosen: L"System Regular" (L"\\??\\Z:\\usr\\share\\wine\\fonts\\jvgasys.fon"/(nil):0)
0090:trace:font:select_font Chosen: L"WenQuanYi Zen Hei" (L"\\??\\Z:\\usr\\share\\fonts\\wenquanyi\\wqy-zenhei\\wqy-zenhei.ttc"/(nil):0)
0090:trace:font:select_font Chosen: L"WenQuanYi Zen Hei" (L"\\??\\Z:\\usr\\share\\fonts\\wenquanyi\\wqy-zenhei\\wqy-zenhei.ttc"/(nil):0)
0034:trace:font:select_font Chosen: L"System Regular" (L"\\??\\Z:\\usr\\share\\wine\\fonts\\jvgasys.fon"/(nil):0)
0034:trace:font:select_font Chosen: L"WenQuanYi Zen Hei" (L"\\??\\Z:\\usr\\share\\fonts\\wenquanyi\\wqy-zenhei\\wqy-zenhei.ttc"/(nil):0)
0034:trace:font:select_font Chosen: L"WenQuanYi Zen Hei" (L"\\??\\Z:\\usr\\share\\fonts\\wenquanyi\\wqy-zenhei\\wqy-zenhei.ttc"/(nil):0)
0024:trace:font:select_font Chosen: L"System Regular" (L"\\??\\Z:\\usr\\share\\wine\\fonts\\jvgasys.fon"/(nil):0)
0024:trace:font:select_font Chosen: L"WenQuanYi Zen Hei" (L"\\??\\Z:\\usr\\share\\fonts\\wenquanyi\\wqy-zenhei\\wqy-zenhei.ttc"/(nil):0)
0024:trace:font:select_font Chosen: L"WenQuanYi Zen Hei" (L"\\??\\Z:\\usr\\share\\fonts\\wenquanyi\\wqy-zenhei\\wqy-zenhei.ttc"/(nil):0)
0024:trace:font:select_font Chosen: L"Noto Sans CJK SC" (L"\\??\\Z:\\usr\\share\\fonts\\noto-cjk\\NotoSansCJK-Regular.ttc"/(nil):2)

在 th06 中界面字体的选择是这样的↓。

# 这个 MS Shell Dlg 显然不是我要的
0024:trace:font:find_matching_face substituting L"MS Shell Dlg",128 -> L"MS UI Gothic",128
0024:trace:font:find_family_from_font_links found entry in system list
0024:trace:font:find_best_matching_face (it=0, bd=0) is selected for (it=0, bd=0)
0024:trace:font:select_font Chosen: L"WenQuanYi Zen Hei" (L"\\??\\Z:\\usr\\share\\fonts\\wenquanyi\\wqy-zenhei\\wqy-zenhei.ttc"/(nil):0)

# 这才是我想找的地方
0024:trace:font:font_SelectFont L"System", h=-12, it=0, weight=0, PandF=00, charset=1 orient 0 escapement 0
0024:trace:font:font_SelectFont DC transform 1.000000 0.000000 0.000000 1.000000
0024:trace:font:find_best_matching_face (it=0, bd=1) is selected for (it=0, bd=0)
0024:trace:font:find_best_matching_face 18 is better for -12 diff was 0
0024:trace:font:select_font Chosen: L"System Regular" (L"\\??\\Z:\\usr\\share\\wine\\fonts\\jvgasys.fon"/(nil):0)

所以这个 System 是什么东西?怎么想都猜不出来吧……最后只好吧 Font Replacement 页面中的所有列举的字体全部尝试了一遍。最后发现是 PMingLiU 。同样在 HKEY_CURRENT_USER\Software\Wine\Fonts\Replacements 手动替换其为 Noto Sans CJK SC ,就可以发现 th06 界面已经完全正常,日志如下↓。

$ cat th06-pmingliu.log |grep select_font\ Chosen
0090:trace:font:select_font Chosen: L"System Regular" (L"\\??\\Z:\\usr\\share\\wine\\fonts\\jvgasys.fon"/(nil):0)
0090:trace:font:select_font Chosen: L"Noto Sans CJK SC" (L"\\??\\Z:\\usr\\share\\fonts\\noto-cjk\\NotoSansCJK-Regular.ttc"/(nil):2)
0090:trace:font:select_font Chosen: L"Noto Sans CJK SC Bold" (L"\\??\\Z:\\usr\\share\\fonts\\noto-cjk\\NotoSansCJK-Bold.ttc"/(nil):2)
0034:trace:font:select_font Chosen: L"System Regular" (L"\\??\\Z:\\usr\\share\\wine\\fonts\\jvgasys.fon"/(nil):0)
0034:trace:font:select_font Chosen: L"Noto Sans CJK SC" (L"\\??\\Z:\\usr\\share\\fonts\\noto-cjk\\NotoSansCJK-Regular.ttc"/(nil):2)
0034:trace:font:select_font Chosen: L"Noto Sans CJK SC Bold" (L"\\??\\Z:\\usr\\share\\fonts\\noto-cjk\\NotoSansCJK-Bold.ttc"/(nil):2)
0024:trace:font:select_font Chosen: L"System Regular" (L"\\??\\Z:\\usr\\share\\wine\\fonts\\jvgasys.fon"/(nil):0)
0024:trace:font:select_font Chosen: L"Noto Sans CJK SC" (L"\\??\\Z:\\usr\\share\\fonts\\noto-cjk\\NotoSansCJK-Regular.ttc"/(nil):2)
0024:trace:font:select_font Chosen: L"Noto Sans CJK SC Bold" (L"\\??\\Z:\\usr\\share\\fonts\\noto-cjk\\NotoSansCJK-Bold.ttc"/(nil):2)
0024:trace:font:select_font Chosen: L"System Regular" (L"\\??\\Z:\\usr\\share\\wine\\fonts\\jvgasys.fon"/(nil):0)

$ cat th06-pmingliu.log |grep PMingLiU
00fc:trace:font:load_system_links L"Tahoma": L"MINGLIU.TTC,PMingLiU"
00fc:trace:font:find_face_from_filename looking for file L"MINGLIU.TTC" name L"PMingLiU"
00fc:trace:font:load_system_links Unable to find file L"MINGLIU.TTC" family L"PMingLiU"
00fc:trace:font:find_face_from_filename looking for file L"NotoSansCJK-Regular.ttc" name L"PMingLiU"
00fc:trace:font:populate_system_links added internal SystemLink for L"Lucida Sans Unicode" to L"PMingLiU" in L"NotoSansCJK-Regular.ttc"
00fc:trace:font:find_face_from_filename looking for file L"NotoSansCJK-Regular.ttc" name L"PMingLiU"
00fc:trace:font:populate_system_links added internal SystemLink for L"Microsoft Sans Serif" to L"PMingLiU" in L"NotoSansCJK-Regular.ttc"
00fc:trace:font:find_face_from_filename looking for file L"NotoSansCJK-Regular.ttc" name L"PMingLiU"
00fc:trace:font:populate_system_links added internal SystemLink for L"Tahoma" to L"PMingLiU" in L"NotoSansCJK-Regular.ttc"
00fc:trace:font:find_face_from_filename looking for file L"NotoSansCJK-Regular.ttc" name L"PMingLiU"
00fc:trace:font:populate_system_links added internal SystemLink for L"MS UI Gothic" to L"PMingLiU" in L"NotoSansCJK-Regular.ttc"
00fc:trace:font:dump_gdi_font_list Family: L"PMingLiU"
00fc:trace:font:dump_gdi_font_list Family: L"@PMingLiU"

$ cat th06-orig.log |grep PMingLiU
00fc:trace:font:load_system_links L"Tahoma": L"MINGLIU.TTC,PMingLiU"
00fc:trace:font:find_face_from_filename looking for file L"MINGLIU.TTC" name L"PMingLiU"
00fc:trace:font:load_system_links Unable to find file L"MINGLIU.TTC" family L"PMingLiU"

所以这个 PMingLiu 是从 Tahoma link 过来的是吗……果然↓……

# [HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\FontLink\SystemLink]

"Tahoma"=
MSGOTHIC.TTC,MS UI Gothic
MINGLIU.TTC,PMingLiU
SIMSUN.TTC,SimSun
GULIM.TTC,Gulim
YUGOTHM.TTC,Yu Gothic UI
MSJH.TTC,Microsoft JhengHei UI
MSYH.TTC,Microsoft YaHei UI
MALGUN.TTF,Malgun Gothic
SEGUISYM.TTF,Segoe UI Symbol

那为啥没有按 Tahoma → MS UI Gothic → WenQuanYi Zen Hei 走?毕竟有 MS Shell Dlg → MS UI Gothic → WenQuanYi Zen Hei 。不过后者是在 FontSubstitutes 指定的。事实证明替换 SimSun 效果也是一样的, SimSun 真是个万能字体。一开始其实尝试过在 FontSubstitutes 直接指定 Tahoma 为 WenQuanYi Zen Hei 或者 Noto Sans CJK SC ,这样并不能解决问题,我还以为跟它没关系了……

搞定了字体,就只要在创建新的 WINEPREFIX 时写入 reg 即可。通常脚本是在 UTF-8 的环境运行,而 reg 文件是 UTF-16 。注意别忘了开头的 BOM ↓。

if [ ! -d "${WINEPREFIX}" ]; then
        mkdir -p "${WINEPREFIX}"

        font=$(fc-match ':lang=ja' -f '%{family[0]}')
        regc="REGEDIT4

[HKEY_CURRENT_USER\\Software\\Wine\\Fonts\\Replacements]
\"PMingLiU\"=\"${font}\"
\"MS ゴシック\"=\"${font}\"
"

        echo -e -n "\xff\xfe" > "${WINEPREFIX}/thcfg.reg"
        iconv --from-code UTF-8 --to-code UTF-16LE <(echo "$regc") >> "${WINEPREFIX}/thcfg.reg"

        wine regedit "${WINEPREFIX}/thcfg.reg"
fi

注意这段脚本如果要在 sh 环境正常运行还需要额外的更改。

by SDUST weilinfox