首页 > 代码库 > 《双星物语》游戏资源格式分析与解包

《双星物语》游戏资源格式分析与解包

作为一款 2001 年发行的老游戏,封包算法应该不会很复杂才对,抱着这样想法的博主,尝试着去分析游戏资源包的封包格式,最后成功将资源解包,下面我们来看看双星物语的游戏资源包封包格式;

游戏资源包以 dat 作为扩展名,一共有两个,分别是 wav.dat 和 BIN.dat,其中 wav.dat 体积较小,先从它下手,用十六进制编辑器打开后,可以看到整齐的文件头部,经过观察发现,整个资源包以【包头】【文件类型信息】【文件信息】【文件数据】这样子的结构组织而成;

首先是【包头】,大小为 8 字节,前 4 个字节固定为十进制数据 12345678(十六进制 0x00BC614E),后 4 个字节为资源包里面所包含的文件类型数量,比如:wav、scr、dec、pal、txm、chr 等等;

接下来是【文件类型信息】,大小为 12 字节,前 4 个字节为该类型文件的文件扩展名,中间 4 字节为该种类文件的文件数量,后 4 个字节为这类文件信息在资源包里面的偏移值;

然后是【文件信息】,大小 16 字节,前 8 个字节是文件名,不包含扩展名,中间 4 个字节是文件大小,后面 4 个字节是文件数据在资源包里面的偏移值;

最后是【文件数据】,这些数据按照【文件信息】里面的描述排列在一起;

根据上面描述,我们可以整理出下面三个最重要的结构体: 

// 包头struct PACK_HEADER{	__int32 nSig;	__int32 nFileTypeNumber;};// 文件类型信息struct FILETYPE_INFO{	char szType[4];	__int32 nOffset;	__int32 nFileNumber;};// 文件信息struct FILE_INFO{	char szFileName[8];	__int32 nSize;	__int32 nOffset;};

接下来,只需要按照上面描述的数据结构去读取资源包,就可以提取出所有的资源文件,遗憾的是,解包之后得到的资源文件,除了 wav 音频文件之外,其它文件都经过了一定的处理;

下面是源代码,用 Visual Studio 创建一个 Win32 控制台工程,然后将生成的 exe 文件放置到与 wav.dat、BIN.dat 两个文件同级的目录中,双击即可解包,解包时会同时建立同名的目录;

#include <windows.h>#include <stdio.h>struct PACK_HEADER{	inline PACK_HEADER()	{		memset(this, 0, sizeof(PACK_HEADER));	}	__int32 nSig;	__int32 nFileTypeNumber;};struct FILETYPE_INFO{	inline FILETYPE_INFO()	{		memset(this, 0, sizeof(FILETYPE_INFO));	}	char szType[4];	__int32 nOffset;	__int32 nFileNumber;};struct FILE_INFO{	inline FILE_INFO()	{		memset(this, 0, sizeof(FILE_INFO));	}	char szFileName[8];	__int32 nSize;	__int32 nOffset;};BOOL WriteDataToFile(const char * szPack, const char * szFile, const char * szExt, const void * pData, const int nSize){	BOOL bRet = TRUE;	FILE * pFile = 0;	char szFileNameOut[MAX_PATH] = { 0 };	if (0 != szPack && 0 != szFile && 0 != szExt && 0 != pData && 0 != nSize)	{		sprintf(szFileNameOut, "%s/%s.%s", szPack, szFile, szExt);		pFile = fopen(szFileNameOut, "wb");		if (0 != pFile)		{			if (nSize != fwrite(pData, 1, nSize, pFile))			{				bRet = FALSE;			}			fclose(pFile);			pFile = 0;		}		else		{			bRet = FALSE;		}	}	else	{		bRet = FALSE;	}	return bRet;}BOOL ExtractPack(const char * szPack){	BOOL bRet = TRUE;	char szFullPackName[MAX_PATH] = { 0 };	FILE * pFilePack = 0;	PACK_HEADER PackHeader;	FILETYPE_INFO * pFileTypeInfoList = 0;	FILE_INFO * pFileInfoList = 0;	void * pFileData = http://www.mamicode.com/0;"%s.dat", szPack);		pFilePack = fopen(szFullPackName, "rb");		if (0 != pFilePack)		{			// 包头			if (sizeof(PACK_HEADER) == fread(				&PackHeader,				1,				sizeof(PACK_HEADER),				pFilePack))			{				// 文件类型信息头				pFileTypeInfoList = new FILETYPE_INFO[PackHeader.nFileTypeNumber];				if (0 != pFileTypeInfoList)				{					if (sizeof(FILETYPE_INFO) * PackHeader.nFileTypeNumber == fread(						pFileTypeInfoList,						1,						sizeof(FILETYPE_INFO) * PackHeader.nFileTypeNumber,						pFilePack))					{						// 文件信息头						for (int i = 0; i < PackHeader.nFileTypeNumber; ++i)						{							pFileInfoList = new FILE_INFO[pFileTypeInfoList[i].nFileNumber];							if (0 != pFileInfoList)							{								fseek(pFilePack, pFileTypeInfoList[i].nOffset, SEEK_SET);								fread(pFileInfoList, 1, sizeof(FILE_INFO) * pFileTypeInfoList[i].nFileNumber, pFilePack);								// 文件数据								for (int j = 0; j < pFileTypeInfoList[i].nFileNumber; ++j)								{									pFileData = http://www.mamicode.com/malloc(pFileInfoList[j].nSize);"%s.%s \n",											pFileInfoList[j].szFileName,											pFileTypeInfoList[i].szType);										fseek(pFilePack, pFileInfoList[j].nOffset, SEEK_SET);										fread(pFileData, 1, pFileInfoList[j].nSize, pFilePack);										WriteDataToFile(											szPack,											pFileInfoList[j].szFileName,											pFileTypeInfoList[i].szType,											pFileData,											pFileInfoList[j].nSize);										free(pFileData);										pFileData = http://www.mamicode.com/0;"wav");	ExtractPack("BIN");	return 0;}

以上代码仅供学习参考使用,游戏中的所有数据,其所有权归游戏开发商所有,请各位不要把资源用于任何商业用途;

本文为原创技术文章,转载请注明出处,谢谢;

本文链接:http://www.cnblogs.com/NekoDev/p/5929644.html 

 

《双星物语》游戏资源格式分析与解包