〇. 游戏安装和运行 & Alterdec编译
1)游戏安装和运行
游戏有三个版本,DVD版,CD版和全年龄版,这里研究的是DVD版,大小是4.33G。
使用NTLEA安装,0.82以上版本即可。个人不喜欢AppLocale。
安装之后执行桌面的快捷方式会报错,这是因为原始的主程序的功能只是调用一下:
rugp.exe ;PF:UGPAPP={age/マブラヴオルタネイティヴ/}
这个マブラヴオルタネイティヴ是SJIS编码。只要把快捷方式改成上面这个就可以了。注意填写rugp.exe的路径
该社的游戏引擎系统就叫做rugp。
2)Alterdec编译
Alterdec是hikobae写的专用资源提取程序,附带源代码。
网址是:http://www.geocities.jp/hiko_bae/alterdec.html
原始程序可能是用VC,我使用Code::Blocks编译,里面存在__int64,用gcc的话要改成long long。加入libpng和zlib应该就能编译通过。
注:下面的部分主要分析Alterdec,而不是游戏本体。
一. 资源文件和Offset
所有资源都在rio文件中,最大2G,超过2G,后缀从002开始增加。如下:
Alternative.rio
Alternative.rio.002
Alternative.rio.003
所有的Offset是将这3个文件当成一个文件来看的,实际Offset还要乘2。
(8byte的最大寻址能力是4G,这种方式rio文件最大寻址能力是8G)
以上内容在函数FILE *OpenRio( const char *filename, dword offset )中。(main.cpp)
二. CLASS、OBJECT
CLASS包含2个成员,name和schema
OBJECT继承CLASS,多了offset和size
其实name指明了数据类型,offset和size指明了地址和大小,schema作用不明。
新出现一个CLASS将压入一个vector中,以后出现重复的CLASS,通过index指明。
以上内容在objectlist.h中
三. 获取objectlist
Object是树状结构的。根是:
"CrelicUnitedGameProject", // name
0, // schema
0x00028d1b, // offset
100 // size
之后调用ReadObject,这个函数根据name,调用相应的函数。
如:ReadRelicUnitedGameProject
以上在main.cpp的main,Decode和ReadObject中。
四. RelicUnitedGameProject
Cache.resize(2)
首先跳过8个字节。
ReadClass (in common.cpp)
读word,如果是FFFF:
读word,是schema。
再后面是Class Name,第一个byte是len,之后数据有压缩。(ReadClassName)
Cache.push_back
如果不是FFFF,那么index = word and 0x7FFF,cache[index]。
Cache.push_back // 也就是说新Class被push了两次。
调用Sub1,flag = 0.
Sub1和Sub2是递归调用,用来遍历Object树。
Sub1: // ReadObjectList
如果flag & 0x0200
返回
N = readword
调用Sub2 N次。
Sub2: // ReadObject
flag = readword // Sub2并没有flag参数,这是传给Sub1的。
如果flag & 7 == 0
如果flag & 8000,跳过1 byte,否则2 byte。
ReadClass
Offset = Decode(dword)
Size = Decode(dword)
Add to ObjectList
Sub1(flag) //一个节点,下面有没有叶子看flag
如果flag & 7 == 1
跳dword
w = readword
如果w == 2d6b
Schema = readword
Name = get delphi-type string
如果w == 1e57
ReadClass // name压缩过
Offset = Decode(dword)
Size = Decode(dword)
Add to ObjectList
Sub1(0) // 一个根,下面肯定有叶子
以上执行完毕后,ObjectList生成。