您的位置:首页 > 其它

重现那款曾经为之痴迷的游戏[1] -- 从资源开始

2008-07-22 14:15 141 查看
预谋

 决定开发流星学院是在2008年04月12日的星期六早上。那时还在成都出差,躺在床上就突发奇想要重现这个游戏。这个游戏虽然很“弱智”,可当时我和我LP还玩得蛮起劲的。我就想啊:要是做出来了以后在家里,大家一起玩,重温一下当年的那种打到装备时候的兴奋啊,也蛮不错的。所以起床后马上就开始动手做。

我这人就是有这个毛病,如果想玩什么就不能只是想想而已,一定要动手去做。

那么,第一件事,就是要获得此游戏中的图片、声音等资源素材,没有这些什么都是空谈。

分析

从狗狗上找到了当年那版客户端,下载下来,游戏程序目录下的文件开始分析。

资源文件类型有 *.tex *.ani *.ini *.wav *.midi 
声音文件格式是midi和wav,这个是现成的,可以直接利用。
*.tex这个根据名称来猜测,应该就是texture
*.ani这个猜测应该就是animation
*.ini貌似是加密了的配置文件,记事本打开全是乱码,暂时不管

这个游戏是2D的,通过IDA反汇编客户端发现使用DirectDraw实现,那么图像资源应该都是图片纹理,如果是动画的话最可能是纹理动画。游戏目录下的*.tex文件应该就是图片纹理,*.ani应该是动画。

用二进制编辑器打开几个*.tex文件分析,发现。不是标准的图像格式,没有BMP头,也没有JPG/PNG的那些节标记,也不像是压缩过(相邻的N字节有很多相同的),所以我猜测这应该是一种自定义的BMP文件,签名有一个自定义头,后面就是RGB数据.


如何分界呢,这个自定义的BMP头是多大?从哪里开始才是RGB数据区?

这个比较容易算出来。首先用二进制编辑器打开一个场景背景图,这个背景图是800*600, RGB表示一个像素常用的就是16位/24位/32位(在心中默念咒语100遍祈祷是24位的RGB,处理起来最简单),用800*600*像素字节数计算出各种可能的RGB数据区大小,与实际文件大小相近的既是。(如果是从内存中某个对象DUMP出来的,也可能被内存对齐影响,)

RGB16 = 800 * 600 * 2 = 960000bytes
RGB24 = 800 * 600 * 3 = 1440000bytes
RGB32 = 800 * 600 * 4 = 1920000bytes

而实际的文件大小是960032,看来是采用的RGB16格式,文件头是32bytes,没有内存对齐。
确定了文件头范围,就该确定表示图片大小在文件头中的最可能的位置了。

比对了数个文件后,确认此位置既是长宽值的保存位置。



像素格式就不用分析了,直接写了一个小程序,读取这个文件,用GDI+拿各种RGB16格式都试一次填充到Image对象,然后输出正常的图像文件,看正常的就是的了。 最后确定,此图像是ARGB4444格式,这种格式很少见啊,我只在PSP和NDS的平台上看到过这种图像的使用,毕竟在不透明情况下色彩总数太少了。

分析完tex文件,就接着分析ani文件。分析ani文件还真是花了我一番功夫,主要是在边界范围的确定上,没有任何可以精确量化的计算过程,完全凭借自己的直觉和10多次尝试,最后终于提取出所有的动画格式了。不啰嗦过程了,我描述不清,帖代码。
void CViewerDlg::ProcessFile(CString strFile)
{
CFile file;
if( !file.Open( strFile, CFile::modeRead, NULL) )
{
AfxMessageBox( strFile );
return;
}

file.Seek( 0, CFile::begin);

int nIndex = 0;
while(true)
{
if( file.GetPosition() >= file.GetLength() - 1 )
break;
file.Seek( 0x18, CFile::current);
unsigned __int32 ulImgWidth = 0;
file.Read( &ulImgWidth, sizeof(ulImgWidth));
unsigned __int32 ulImgHeight = 0;
file.Read( &ulImgHeight, sizeof(ulImgHeight));
ulImgHeight += 1;

unsigned __int32 ulDataSizePerLine = 0;
file.Read( &ulDataSizePerLine, sizeof(ulDataSizePerLine));
file.Seek( 0x4, CFile::current);

Bitmap bmp( ulImgWidth, ulImgHeight, PixelFormat32bppARGB);
Graphics gp(&bmp);
gp.Clear(Color::Transparent);

BYTE * pSrc = new BYTE[ulDataSizePerLine];

for( UINT y = 0; y < bmp.GetHeight() - 1; y++)
{
Rect rect( 0, y, bmp.GetWidth(), 1);
if( file.Read( pSrc, ulDataSizePerLine) <= 0 )
break;

BitmapData stBmpData = {0};
if( bmp.LockBits( &rect, ImageLockModeWrite, PixelFormat32bppARGB, &stBmpData) == Ok )
{
LPDWORD pDest = (LPDWORD)stBmpData.Scan0;

for( UINT x = 0; x < bmp.GetWidth(); x++)
{
WORD wPixel = pSrc[2*x] | pSrc[2*x + 1] << 8;
pDest [x] = Convert4444(wPixel);
}

bmp.UnlockBits(&stBmpData);
};
}
delete [] pSrc;

CLSID pngClsid;
GetEncoderClsid( L"image/png", &pngClsid);
nIndex++;
CString strTemp;
strTemp.Format( _T("%s.%d.png"), strFile, nIndex);
bmp.Save( strTemp, &pngClsid);
}

file.Close();

}
提取

分析完成后就可以开始批量提取了,没什么技术含量。就是在分析的基础上写提取工具。只是在提取tex文件的过程中,发现有些图片提取出来的图片完全乱色了。

回过头重新分析,居然有2种RGB格式 565和4444,而在文件头中有一个值标明了此文件RGB值类型

 

今次就写到这里,如果你是这款游戏的开发者/策划者,并偶然看到此贴,请与我联系:) 我需要一点数值设计的资料。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐