在游戏中这部分的解密,比较容易实现,就是对整个文件加密,游戏启动时把加密文件读入内存进行解密,然后把解密数据传到解析器进行解析。一些由游戏产生的需要保存的数据,我用XML进行保存。加解密思路也如上。
但是,对于图片、动画,粒子、cocostudio1.6导出的UI 等数据,加密就不那么简单了。因为,像 Sprite::create 这样的接口,并没有提供一个从内存获取纹理数据来初始化精灵的方式,而是直接从磁盘文件中读。用户在外部是无法干预文件数据的读取载入的。
游戏资源的加密要怎么做???只有修改引擎了。- -! 我觉得,修改引擎并不是一个好的做法。引擎应该由引擎提供商来维护,而不是靠用户自己来动手。用户自己动手会造成项目维护升级困难。自己把引擎改得乱七八糟,想升级引擎到新的版本会变成很麻烦。就算是修改了一点,升级引擎版本一次,就要做一次修改,这样也很麻烦。
要修改引擎,首先要跟踪调试,以cocos2d-x 3.4 作为试验版本,从Sprite::create入口,一步步跟下去,看看引擎是在哪里载入文件数据的。
经过调试跟踪,Sprite::create的调用堆栈如下:
getData
FileUtilsWin32::getDataFromFile
Image::initWithImageFile
TextureCache::addImage
Sprite::initWithFile
Sprite::create
在windows上,精灵载入图片,是调用到了
CCFileUtils-win32.cpp 这个文件中的
static Data getData(const std::string& filename, bool forString) 函数。
这个函数是一个非类成员静态函数。
再调试下其他的数据载入,cocostudio1.6做的动画的调用堆栈是:
cocos2d::FileUtilsWin32::getFileData
cocostudio::DataReaderHelper::addDataFromFile
cocostudio::ArmatureDataManager::addArmatureFileInfo
经过了多种文件类型载入的跟踪调试后,总结,基本上文件的载入函数有2个,都在CCFileUtils-win32.cpp文件中,
1.FileUtilsWin32::getFileData
2.getData
要做解密的话,就是修改这2个函数了。值得注意的一点是:getData函数的签名是:
static Data getData(const std::string& filename, bool forString)
forString这个参数,用于标识读入的文件是不是一个文本文件。如果forString为真的话,buffer就要多分配一个字节,用来放置C语言的字符串结束符 \\0
截图一下引擎的代码:
要做解密,我们的解密数据内存也要用forString来判断是否多分配一个字节的内存。FileUtils单件类,很多函数是虚函数。FileUtils::getInstance,在Windows平台上,返回的是 FileUtilsWin32子类对象。在Android平台上,返回FileUtilsAndroid子类对象。
Cocos2d-x 3.4 实现在Windows和Android平台上的解密需要修改2个文件:
Windows 平台的:cocos\\platform\\win32\\CCFileUtils-win32.cpp
Android 平台的:cocos\\platform\\android\\CCFileUtils-android.cpp
这2个文件里面都有 getData 和 getFileData 函数,都需要修改之。
文件数据的读取在不同平台上有不同的实现,如果要在目标平台上做资源加密,就需要修改目标平台上的读取实现。FileUtils是一个文件读取基类,提供有默认的实现,一些平台会提供特定的实现。通过多态,FileUtils让我们的游戏客户端代码不需要对特定平台做特定处理,也不需要关心FileUtils子类的类型。
加密解密支持工具
一般要做资源数据加密,大体会做2件事:
1.写一个工具,能对磁盘文件进行加密。这个工具,可能需要遍历文件夹、可批量选择文件等功能。
2.在软件程序中加入解密功能,对工具加密后的数据进行解密。
工具能方便操作、提高生产力,很重要。
这里,我自己做了2个工具。