This article contains 1,966 words.It may takes you about 7 minutes to read.
Copyright: 署名-非商业性使用-相同方式共享
|
CC BY-NC-SA 2.5 CN
声明:
游戏破解和移植行为会损害游戏厂商的利益
本文仅讨论一种可能的方法,不会公开任何文件的下载
背景
由于这个长长的假期,我接触到了サクラノ詩这样一部优秀的作品。遇到了好的作品,就会不由自主地想要把它推荐给别人。但是,サクラノ詩只有 Windows 版本,如何将他推荐给 Linux、macOS、Android 甚至 Chrome
OS 平台的同学呢?
因此我们需要移植。移植即为将一个平台上运行的程序修改以在另一个平台上运行。对于一个普通的二进制可执行文件,移植几乎等同于反编译 + 重写程序 ,再考虑到可能存在的壳,移植的可能性几乎为零。
但是 galgame 的游戏剧本和资源一般与游戏主程序独立(这也是 galgame 汉化的前提),我们可以将剧本和资源提取出来,经过处理,再用另一个程序进行解析,实现接近的效果。由于没有追求和源程序完全等价,因此工作量减少了许多。
本文的目标是将サクラノ詩由 BGI 引擎移植至 RenPy,实现全平台通用。
参考资料
Galgame
汉化破解初级教程:以 BGI 为例,从解包到测试
在前年处理素晴日的时候就参考了这篇文章很多。BGI 引擎没有大变,这篇文章一直没有过时。文章里的资源处理很有用。
《素晴日》移植笔记
这篇文章是讲 BGI 引擎的 ONS 移植的,本文没有用 ONS 是因为
ONS 难用
RenPy 的全平台通用性更好。素晴日 ONS 版文件里留下了许多注释,对于这次移植起到了很大作用。
Ren’Py 的参考文档
移植需要将剧本翻译为 RenPy 可以解析的语言。能实现多少演出效果也取决于对 RenPy 的熟悉程度。因此 RenPy 的参考文档要反反复复看上好多遍。
CROSS†CHANNEL
中文化(汉化)项目
C+C 的全平台化使用了 RenPy 引擎,并且该项目将其 RenPy 移植的成果公开发布在了 Github 上。其源码里对于一些情况的处理有很大的参考价值。
拆包
BGI 引擎万年不加密,用 fxckBGI、AnimED、GARbro 或是其他工具或是手动拆包都可以。
BGI 引擎剧本文件一般打包在游戏目录下的 data01xxx.arc 里,用工具提取可得到一堆无扩展名、以章节名为文件名的文件,这就是剧本文件。
其他的文件也用类似的方法提取,根据文件格式放到对应的目录。
剧本处理
剧本文件的结构在澄空那个教程上已经讲得很清楚了,这里直接用前人留下的工具 Bgi_asdis.zip 将剧本文件转换成类汇编语言。
得到的.bsd 文件内容大概长这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 line ("00_op_01.bss" , 416 );push_dword (1 );push_dword (1 );push_dword (0 );push_string ("直哉" );push_string ("「少し……気持ちが悪いんだ……」" );msg_::f_140 (); line ("00_op_01.bss" , 418 );push_string ("ked_000005" );snd_::f_1a9 (); line ("00_op_01.bss" , 420 );push_dword (1 );push_dword (1 );push_dword (0 );push_string ("圭" );push_string ("「どうした? 気分が悪いのか? 直哉?」" );msg_::f_140 (); line ("00_op_01.bss" , 423 );push_dword (1 );push_dword (1 );push_dword (0 );push_string ("直哉" );push_string ("「ああ……そうかもしれないな……」" );msg_::f_140 (); line ("00_op_01.bss" , 427 );push_dword (1000 );push_string ("evb000b" );grp_::f_280 (); line ("00_op_01.bss" , 432 );push_dword (1 );push_dword (1 );push_dword (0 );push_dword (0 );push_string (" 俺は空を仰ぎ……舞い散る桜を見つめる。" );msg_::f_140 ();
有点编程的同学大概能看懂这段程序在干什么。压栈压栈再调用函数,函数的参数即为前面入栈的参数。
写一个大概这样的脚本把这段剧本变成正常的调用函数
1 2 3 4 5 6 7 8 9 stk=[] for line in lines: if line[0 :4 ]=='push' : stk.append(something) elif line.find('f_xx' )!=-1 : something=[stk.pop(),stk.pop(),...,stk.pop()] print ('f_xx(' + ',' .join(something) + ')' ) elif ...: ...
类似这样,可以把之前提取到的类汇编剧本变成这样
1 2 3 4 5 6 f_140("「少し……気持ちが悪いんだ……」" ,"直哉" ,0 ,1 ,1 ) f_1a9('ked_000005' ) f_140("「どうした? 気分が悪いのか? 直哉?」" ,"圭" ,0 ,1 ,1 ) f_140("「ああ……そうかもしれないな……」" ,"直哉" ,0 ,1 ,1 ) f_280('evb000b' , 1000 ) f_140(" 俺は空を仰ぎ……舞い散る桜を見つめる。" ,0 ,0 ,1 ,1 )
这下就看起来直观多了
把输出文本的地方稍微改一下(主要是 f_140() 这个函数)以符合 RenPy 的格式
1 2 3 4 5 6 直哉 "「少し……気持ちが悪いんだ……」" f_1a9('ked_000005' ) 圭 "「どうした? 気分が悪いのか? 直哉?」" 直哉 "「ああ……そうかもしれないな……」" f_280('evb000b' , 1000 ) " 俺は空を仰ぎ……舞い散る桜を見つめる。"
这段剧本已经符合了 RenPy 的格式。
函数完善
运行这段代码没有 BGM 没有语音没有立绘没有 CG,换句话说只能显示文本,其他的一切效果都没有(因为还没做)。
统计剧本文件中出现的函数,一共有 120 个。如果没有正确的定义这些函数,函数对应的功能就不能实现。
素晴日 ONS 移植版中有一部分函数的 ons 实现,可以用作参考。其他的函数需要先确定功能再用 RenPy 实现类似的效果。
此外,类汇编剧本中的 line() 表示的是行号,和通过修改文件开启的 DEBUG 模式里显示的行号是一致的(利用这个可以比较方便地找到)。通过这个特性也可以方便地定位演出效果和函数的对应关系。
动画相关的函数像实现文本放大居中等演出效果的函数的参数的确定需要反复观察对比才能确定。
和立绘相关的函数的处理也是个大坑。
界面处理
RenPy 推荐使用 frame、vbox、hbox 等界面语言描述界面,但是为了使移植版和原版表现效果一致(尽可能使用上原版的素材),最终选择直接用绝对 pos 来确定图片和按钮的位置。先截图用 ps 确定按钮的位置,再直接把按钮固定到对应的位置上。简单粗暴。
1 2 3 4 5 6 7 8 imagebutton: pos(116 ,514 ) idle im.Crop("gui/button/SGTitle000000.png" ,(0 ,0 ,114 ,63 )) hover im.Crop("gui/button/SGTitle000000.png" ,(114 ,0 ,114 ,63 )) selected_hover im.Crop("gui/button/SGTitle000000.png" ,(228 ,0 ,114 ,63 )) hover_sound "music/sse000000.ogg" activate_sound "music/sse000001.ogg" action [Stop("music" ),Start()]
需要处理的界面有主界面、游戏界面、设置界面、存档读档界面、对话历史界面、鉴赏界面。处理方法相同。
资源压缩
BGI 引擎的压缩算法很玄学,不到 3G 的 arc 文件全部提取出来占用了 11G 的空间。体积这么大打包也成了困难的事。所以需要对资源文件进行压缩。
RenPy 支持的图片格式有 png、jpg、webp。经过实际测试,将图片压缩为 webp 不仅不会丢透明图层、画质损失低,还达到了 10~20% 的压缩率,效果好到惊人。
压缩使用了 python 的 PIL 库,遍历源文件目录用 PIL 打开文件再在输出目录用 webp 格式保存,代码很好写。
语音文件占 1.5G 左右,格式为 ogg。通过 ffmpeg 将码率压缩到 48kbps,文件体积缩小了一半。
最终将 11G 的资源文件压缩到了 2.5G。
打包
通过 RenPy 自带的工具可以方便地进行打包。
Windows、Linux、macOS 打包都很顺利,一键全自动(其实只是把 python 环境、RenPy 库和游戏文件加到同一个压缩包里)。
在打包 apk 时遇到了内存不足的问题,开了 16g 的虚拟内存问题解决。
调试
因为是边做边试的,打包完成运行时没有遇到什么问题。