本文旨在说明修改游戏存档的思路、编程方法和一点技巧,并无其他不良企图。如果仅仅为了修改游戏,FPE、金山游侠等更为专业。
前言
大多数程序员都玩过游戏,也或曾想过修改游戏,笔者也不例外。我通常不希望自己受困于游戏中的经验值、金钱之类的,于是采用修改游戏存档文件的方法,自己动手修改比起使用金山游侠等更有乐趣。毕竟有时候只要享受一下游戏的情节就够了,把大量的时间花费在增加经验值、赚钱方面太不合算了,毕竟时间有限而游戏无限!方法嘛,使用老牌的UltraEdit(以下简称UE),当然还需要配合“计算器”进行十进制和十六进制的转换。时间长了,也觉得繁琐,何不自己动手写一个针对游戏存档文件的修改器而一劳永逸?笔者比较喜欢C++,如果你有一定的C++基础,跟我走吧!
笔者的电脑:AMD XP1700+,Windows2000(sp4),Borland C++ Builder 6(sp4)
手工修改游戏存档文件的方法
游戏存档文件大多使用二进制格式,这样对于读取和保存数据都比较方便。可使用Windows的“计算器”来看看10进制和16进制的区别:采用“科学性”模式,在10进制模式下输入数据,然后切换到16进制就行了。
不过就算这样转换,看起来还是不很直观,因为在游戏存档中并不是如此显示的。
那么用C++如何表达的呢?下面这个小程序演示了如何读写二进制整数。
#include <iostream>
#include <fstream>
using namespace std;//标准库所在的空间
int main()
{
fstream BinFile("",ios::in | ios::out | ios::binary);//读+写+二进制模式
int i=1234;
BinFile.write(reinterpret_cast<const char*>(&i),sizeof(int));
//reinterpret_cast是C++的强制转换,这里把整数的地址强制转换为const char*,
/
/与C 的(const char*)&i 作用相同,但是reinterpret_cast更加含义明确。
i=0;
BinFile.seekg(0,ios::beg);//重新指向文件开头准备读取
cout<<"i="<<i<<’\n’;
}
用UE打开切换到二进制模式,是这样子的:
在计算器中看到的是04D2,在UE 中看到的是D204,这就是笔者所谓的不直观性。因此,如果你要在某个游戏存档文件中间(扩充开来就是二进制文件)寻04D2这个数值,到上图显示的地方就对了。笔者初期手工修改存档也是这样的,比较麻烦。
下面这个小程序表明了模拟UE在二进制文件中寻
整数的原理:
曲姗姗
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
fstream BinFile("",ios::in | ios::out | ios::binary);//读+写+二进制模式
const int i=87654;
BinFile.write(reinterpret_cast<const char*>(&i),
sizeof(int));//强制转换,把i用二进制方式写入文件
BinFile.seekg(0,ios::beg);
//重新指向文件开头,准备读取
char ch;
ad(&ch,sizeof(char)))//读取所有字符
cout<<static_cast<int>(ch)<<"\t";//显示
//static_cast是C++的静态转换,与C的(int)ch作用相
//同,但是static_cast意思表达更清楚。
cout<<’\n’;
灯饰十大品牌//下面把i的地址转换为字符串地址,并用char方式依次读取,主要是比较两者读取的结果是否相同.
胡悦鑫图片
const char* P=reinterpret_cast<const char*>(&i);
for(int i=0;i<sizeof(int);++i)
cout<<static_cast<int>(P[i])<<"\t";
}
用C++制作自己的游戏修改器(上b)vc++ 2007-11-29 16:27:05 阅读13 评论0 字号:大中小
手工在存档文件中使用UE中来查某个数值的时候,可能到好多地方,靠一个一个查然后记录下地址可真费眼神。写个程序来自动寻指定的数值,并且记录下地址吧!本文所述的地址都是从0开始的,而且都以十进制方式输入输出。
template<class T>
class CheckBinaryFile
{
public:
typedef fstream::off_type AddressType;
CheckBinaryFile();
void Run();
private:
static const int MaxByte=sizeof(T);
const int CharSize;
EInputStream CIN;//我自己写的一个加强输入流string FileName;
T OldData;
int ByteNumber;
mutable bool InputIsOk;
mutable ifstream BinaryFile;
mutable list<AddressType> AddressList;
void Input();
int Check() const;
void SaveAddressToFile(ostream&) const;
void AutoModifySave(const T&) const;
};
template<class T>
const int CheckBinaryFile<T>::MaxByte;//定义静态整型常量
范伟的老婆
这是自己定义的一个类,下面逐一解释:
template<class T>
T代表要寻的数据的类型。当然,这个程序只是寻整数(经验值、金钱都是整数!),但我不排除以后要查其他类型的数据。为了可扩充性,使用了模板。
typedef fstream::off_type AddressType;
我要到数据在文件中总有地址,这个地址是什么类型呢? int还是long,或者是其他类型?fstream有一个类型叫off_type,应该是偏移类型的含义,在这里我把这个类型叫做AddressType。
static const int MaxByte=sizeof(T);
这是一个静态整型常量,表示T的大小(最多有多少字节),比如在我的机器上,sizeof(int)=4。T的大小在编译的时候就确定,而且它不能被修改(const),对于所有查类型相同的CheckBinaryFile,这个数值是唯一的,共享的(static)。
构造函数:
template<class T>
CheckBinaryFile<T>::CheckBinaryFile():CharSize(sizeof (char)),CIN(cin)
{ InputIsOk=true; Input(); }
CharSize 为sizeof(char),把cin 绑定到CIN。由于CharSize是常量,必须在构造函数的初始化列表中设定。
预设输入状态,调用输入函数:
template<class T>
void CheckBinaryFile<T>::Input()
{
cout<<"Binary file name:\t";
CIN>>FileName;
BinaryFile.open(FileName.c_str(),ios::in | ios::binary);
姜文主演的电视剧
996工作制是什么意思if(!BinaryFile){
InputIsOk=false;
cerr<<"Open file failed.\n";
return;
}
cout<<"The integer you want to search:\t";
CIN>>OldData;
cout<<"Byte number(1--"<<CheckBinaryFile<T>::MaxByte<<"):\t";
CIN>>ByteNumber;
if(ByteNumber<1 || ByteNumber>CheckBinaryFile<T>::MaxByte) {
//字节数错误,调整为最大值
ByteNumber=CheckBinaryFile<T>::MaxByte;
cout<<"Byte number was amended to " << CheckBinaryFile<T>::ByteNumber <<’\n’;
}
}
提示用户输入二进制存档文件,用只读+二进制模式开启。如果失败,设置输入状态为