前言
我在「游戏报告」系列多次提及,HLTB 部分不会计入 Gal 相关内容。 这方面其实也有不少想写的,但一直苦于没有合适的题材。 常见的引擎解包基本都有现成的工具, 逆向则受限于我完全不够用的经验和拙劣的 Win32 平台开发水平,无从谈起。 受 LLM 热潮影响,机翻/汉化方面的教程算是满天飞, 像 GPT-3.5/4、Qwen2.5-32B、Claude-3.7-Sonnet/Opus 这种通用模型不说, 现在还有 SakuraLLM 和 GalTransl 这种(半)自动工具,搞翻译的条件真是今非昔比。
上个月重新鼓捣了一个 Ren’Py 游戏(虽然又是只做了个开头就弃坑),又想起来这么回事。 刚好过年时候打的(歪果仁做的)国风修仙 gal Cross Realms 更新 v0.2 版本, 惯例自定义优化的时候又想到这个,于是时隔多月的 #gal 相关文章就决定是它了。
如果你注意到网页 URL 的 Galgame Customization Checkup,这个 acronym(首字母缩写)就是 GCC,算是玩了个文字游戏(玩 lfs-vbox 玩的)。
序言
因为前言都在说废话,再插个序言。 这篇文章主要就是介绍如何通过修改游戏文件,让游戏的各种配置更加符合预期。
听起来可能很官方,感觉云里雾里的,随便举几个🌰:
Galgame 数以万计 3,肯定不能一个个讲过去,所幸游戏引擎数量要少得多,同一引擎的方法基本通用,大多也就是密钥和加密方式改一改,对于自定义配置而言影响不大。
引擎
主要用作自己的备忘录,先附上 TLDR,再详细解释。
RenPy
🗒 Tldr
- easy-skip.rpy
- xdg-dir.patch (on demand)
- 流程图
Easy-Skip
RenPy 默认的按键配置已经足够好,唯一让人诟病的就是鼠标中键和右键,与霓虹 gal 常见的右击隐藏窗口,中键唤起设置不同,而且默认鼠标滚轮下滑是 rollforward,不是 dismiss4。
使用 easy-skip.rpy 恢复正常的行为,放到游戏的 game
目录即可,运行时会自动编译成 rpyc:
# 定制按键映射
init 999 python:
renpy.config.dismiss_enabled = True
try:
# 交换鼠标中键和右键的功能
config.keymap['hide_windows'].remove('mouseup_2')
config.keymap['game_menu'].remove('mouseup_3')
# 注意要先都移除再添加
config.keymap['hide_windows'].append('mouseup_3')
config.keymap['game_menu'].append('mouseup_2')
# 把鼠标滚轮下滑变成跳转下一句,注意是 dismiss 不是 skip
# config.keymap['rollforward'].remove('mousedown_5')
config.keymap['dismiss'].append('mousedown_5')
except:
pass
init 999
表示这一项会放在最后初始化,注意不是优先级(越高越优先)!如果过早初始化,那么开发者写的按键映射可能会覆盖掉自己定制的。Ren’Py 中并没有先来后到的说法,后来的会直接替换掉原先的值。
XDG-Dir
这算是研究 XDG Base Dir Spec 的副产品,旧版本 Ren’Py 默认存档位置在 ~/.renpy
,对希望 $HOME
保持整洁的用户而言看着很难受,很可惜,这点实际上是 wontfix。
对于 Ren’Py 7.5+ 的游戏,可以使用 RENPY_PATH_TO_SAVES
环境变量修改默认的存档路径。
目前最新版本已经到了 7.8/8.3,新游戏基本不需要担心。
但很多停更/完结的老游戏,官方修复是指望不上了,实际上打 patch 也相当简单,只需要在 renpy/game.py
添加几行代码即可,打完补丁游戏会先尝试 XDG_DATA_HOME
环境变量,如果不存在再 fallback 到上文提到的 RENPY_PATH_TO_SAVES
:
--- renpy/game.py
+++ renpy/game.py
@@ -105,6 +105,12 @@
# No save directory given.
if not save_directory:
return os.path.join(gamedir, "saves")
+ # Try $XDG_DATA_HOME first, if any
+ if "XDG_DATA_HOME" in os.environ:
+ return os.environ["XDG_DATA_HOME"] + "/renpy/" + save_directory
+ # Then fallback to $RENPY_PATH_TO_SAVES as failsafe
+ if "RENPY_PATH_TO_SAVES" in os.environ:
+ return os.environ["RENPY_PATH_TO_SAVES"] + "/" + save_directory
# Search the path above Ren'Py for a directory named "Ren'Py Data".
# If it exists, then use that for our save directory.
流程图
即 renpy-graphviz,在 Ren'Py 初印象#开发 中有所提及,不再赘述。 实际上很多选择支复杂的 Ren’Py 游戏也会提供官方攻略,大部分游戏选项都没几个,完全用不上流程图。 这个使用场景还是比较有限 - -
Kirikiri
🗒 Tldr
- data.xp3/system/Config.tjs
- diff > patch.xp3
- startup.tjs, cue 手机版
吉里吉里的各种资料和工具相当多,这里就不班门弄斧了,下面说的操作 GARbro(原版,Mod)基本都能干。
一般而言,你想修改的文件只有 data.xp3 中的 system/Config.tjs,也就是改个标题/字体,开启 debugMenu 啥的。为了在手机端运行可能会魔改一下 startup.tjs,但后者超出了本文的范围,不作讨论。
顺带吐槽一句,很多 gal 的「手机版」、「高压版」,除了把图片转成 WebP,视频码率也是往死里压,图片错位不要太常见,真的除了便携毫无优势……不要只看修复了多少多少原版的 bug,愿意花时间做手机版,发现那么点小文本错误不是很正常。
前几年做商务 brochure,退休的新中国第一批记者帮我校对,每次都圈点画出几十处错误,前后上百版改了多少处我都不敢想。不管怎样,你修改完对应文件,直接封包,重命名为 patch.xp3(patch2.xp3
/patch3.xp3
/patch4.xp3
,以此类推),大多数 Krkr 游戏都能正常读取。如果开发商/汉化组通过魔改 system/Initialize.tjs 修改补丁的读取逻辑,我建议就别折腾了……
因为对 Krkr 开发不太熟(最开始学的 Ren’Py,惊为天人,回头再看 Kirikiri/NVLMaker,确实是看不上),这部分也没多少好说的,但资料很多,想改什么随便搜搜就有,只要引擎能实现,都不难找到。
同理,对于 Artemis 引擎的修改也类似,不再赘述。
TyranoScript
🗒 Tldr
修改键位:
<game>\resources\app.asar.unpacked\data\system\KeyConfig.js
,其他以此类推。
暴龙引擎🦖也是另一个常用的 gal 引擎,不过 Steam 上的 TyranoBuilder 好久没更新,depot 更新还是 22 年 9 月,GitHub 倒是零零散散有更新,但(在有全方位吊打的 Ren’Py 的前提下)都用暴龙了,不能指望人家还会特地上这找补丁= =
和 WebGal 以及其他一堆有的没的引擎一样,本质还是浏览器套壳,图形化编辑器操作都很繁琐,玩不出什么花样,当然这是从开发角度说的。由于是浏览器,同样会受到 policy-templates 限制,详见 浏览器调教指南 - Chromium 篇#配置插件。
跑题了,TyranoScript 底层还是难用的 KAG,配置项和 KiriKiri 基本一样,前置条件无他,唯解包尔。
封包基本就三种情况:
- 不封包,万事大吉,直接开整
- 封入 exe,后缀改 zip 解压,如果不行就运行游戏然后转到
%temp%\nw___
,复制到游戏目录 - 封入
app.asar
,首先尝试 WinAsar,如果不行直接使用 npm 包
# 这样是错误的
$ npm install -g asar
npm WARN deprecated asar@3.2.0: Please use @electron/asar moving forward. There is no API change, just a package name change
# 这样才是正确的
$ npm install -g electron/asar
# 解包
asar extract app.asar app.asar.unpacked
有的可能还是解不出来,但本文的重点是自定义配置,不是完全解包,所以忽略这点。
修改键位,需要魔改 <game>\resources\app.asar.unpacked\data\system\KeyConfig.js
,其他的注释都很详细,唯一的坑就是不要手贱把配置文件里原有的 ;
去掉,这玩意儿不是注释……
其他
剩下一些零零散散的内容,就想到什么写什么,单纯的 bullet list:
- 资源解压
- 使用 PeaZip,自带(非常基础的)密码管理器,方便快速选择对应密码
- 部分资源的格式比较诡异(比如 .tar.zst,或者 .tar.zst.001 这种分卷压缩包),使用 file-transfer 提到的 Thunar Custom Action 快速解压,Windows 也可以参考文中其他部分实现一样的效果
- 绕过语言/时区/地区检测、DVD 验证、DRM,这些和自定义没什么关系,更侧重于系统支持,主要是 YU-RIS、Entis GLS 之类的
- 文本既读率统计
- SiglusEngine 有个很好用的小工具 SiglusCounter,RealLive 也有类似的,毕竟都出自 Visual Arts (Key)
- 很多游戏自身也带有文本既读率、游玩时长等统计数据,不需要第三方工具(也就没必要自定义)
- Kirikiri 可通过解混淆存档来获取游戏进度,但没有直接统计文本既读率的工具,感兴趣的可以参考 探究 kirikiri 引擎的存档文件 .ksd/.kdt 内容格式(解析)和存档机制 和 KirikiriDescrambler 手搓 5
- Ren’Py 同样自带,开发者可以调用
renpy.count_seen_dialogue_blocks()
,用户可以在游戏运行时 Shift + O 打开 Developer Console 查看,三句代码的差异见文档 6
renpy.count_newly_seen_dialogue_blocks()
renpy.count_seen_dialogue_blocks()
renpy.count_dialogue_blocks()
- 少数游戏 7 如果在特殊日期(角色生日、
日本节假日、游戏关键事件发生时间等)启动,会触发特殊对话。调整系统时间当然可以,但如果对话有几十条还想一次性全部看完,NirSoft 的 RunAsDate 就是个很实用的小工具,Win2000 - Win11 全都支持。需要注意,带这种功能的 gal 大概率还是 32 位程序,不要搞错弄成 RunAsDate-x64 启动了= = - 对于养成游戏或者需要经常移动的游戏,可以用 Graphiviz 画地图
- Ren’Py 有 renpy-graphviz,前文已提及,不再赘述
- 七月份打 DOS 经典游戏『红楼梦十二金钗』8 曾用到,不过地图只能反映相邻元素的方位(就是上下左右),斜对角的方位是不准确的,而且设计者估计没想过布局在现实中不可能实现……顺便吐槽游戏为了追求真实还用的十二时辰计时,卯时起床酉时天黑,子时会自动回家,一天就那么点时间,外加每条线路的前置条件,炼丹还要到各地裁素材,不画地图真不好规划= =
- 本文关注 galgame,
像 妹相随 用的 Wolf RPG Editor 和更加烂大街的 RPG Maker 之类的 RPG 引擎就不管了,也没什么可自定义的,数值修改要么很简单要么很复杂强烈推荐 Mtool,原本我不喜欢 RPG Maker 做的 SIM/SLG/RPG 的原因一方面是以前玩得太多,另一方面就是数值崩坏很严重,拿 CE 修改也得一个个猜。而 Mtool 通过倍速、自动存档、快捷键映射、变量读取/修改/锁定,完美解决了后者,有空估计我也会扩展一下视野。 - 而像 Unity9、Unreal、GUST(光荣特库摩)等游戏的自定义基本等同 mod,这里也不再一一赘述。
- Godot 在 gal 领域用得也不多,也就活跃在 itch/Patreon,时不时烂尾的欧美 SLG 会用,但主要是为了缩减体积(PCK 比 Ren’Py 的 RPA 压缩率高多了),实际运行效率和 Unity 一个等级,远逊于 Ren’Py。自定义的方式自行类推,还是本文讲的那些,无非是从 KAG/TJS/Python 换到 C#/GDScript
结语
不管你有没有注意到,我在 #前言 说到的 GCC acronym,其实中文标题也有对应的梗。 不相信?
💡 Tip
Galgame Zi ding yI Pei zhi you hua
所以说是 GZIP 也不是不行,欸嘿~(∠・ω< )⌒☆
Ctrl 也不行的情况比较少见,但是很多游戏默认只能 Ctrl 快进全部文本,和我习惯的「鼠标滚轮快进到下一文本」的节奏天差地别 ↩︎
说的就是 FAVORITE o( ̄ヘ ̄o#) 当然你也可以用 Magpie 放大,但毕竟需要计算,存在延迟,多周目快进已读的时候会一卡一卡的 ↩︎
截止 2024-09-25,VNDB 数据为 VN 50874,release 120994。由于 VNDB 对「视觉小说」有严格的定义,「美少女游戏」实际数目只多不少(上不了批评空间只能拿这个凑合) ↩︎
这里就不得不吐槽 Ren’Py,不管是否已读都跳转下一句,这个操作叫 dismiss(相当于大多数 gal 的 Ctrl),而不是 skip……后者只会跳过已读文本,而不会跳过未读(相当于大多数 gal 的鼠标左击和 Space/Enter)。更难受的是,Ren’Py 默认值并不是这俩,而是 rollforward,就是你用滚轮回顾历史文本(不弹出 ADV Mode,即那个大框框)时,可能滚过头了,这时可以下滑滚轮滚回去。听起来没什么区别?Rollforward 实际效果就是完全没用,正常游戏时都不会跳转下一句(不管是否已读),只有回顾历史文本才有用…… ↩︎
注意存档不一定是
datasu.ksd
/datasc.ksd
,也可能在图片预览缩略图,这点是个大坑…… ↩︎当然 Ren’Py 导出的原始包默认关闭 Developer Console,可以写个脚本强制开启,或者通过 bug 触发报错弹窗调用,解包工具也基本都提供这个功能,反正都很简单 ↩︎
Saga Planets 就很喜欢这么搞,由于有 SiglusCouter,这种彩蛋更容易被发现 ↩︎
顺带一提,对逆向或者鉴赏模式补丁感兴趣的可以看 tricks.one 的游戏资源分析系列,补丁在最后一篇,作为看完注释的奖励,附上我做的精校带注释版全地图 ↩︎
包括 NVL Maker/CatSystem for Unity,前者直接看 KiriKiri,后者直接看 CatSystem2,也就是为跨平台做了点处理 ↩︎