本系列学习教程使用的是cocos2d-x-2.1.4(最新版为3.0alpha0-pre) ,PC开发环境Windows7,C++开发环境VS2010

一、对数据进行编解码

在上一期中,我们使用了CCUserDefault对游戏数据进行存储与读取,但是细心的我们肯定会想到,其游戏数据

存储文件是否安全呢?通过上一期对CCUserDefault的讲解,想必大家也很容易看出Cocos2D-X是以键值对进行存储

的,其存储方式其实是个xml文件,也就是说,游戏数据并不是那么安全。

这里我们一起来学习一个简单的对游戏数据进行加密的方法:使用Base64编码解码来实现。

对于Base64,由于篇幅限制,这里就不过多的介绍了,不是很熟悉的话可以自行查阅相关资料。

二、Base64C++代码

下面首先来看看Base64的C++版本的代码,我们将编码解码封装在一个BaseData类中,这个类的代码说明如下:

BaseData.h

  1. #ifndef EDCodeTest_BaseData_h
  2. #define EDCodeTest_BaseData_h
  3. #include <string>
  4.  
  5. std::string saveData( char const* , unsigned int len);
  6. std::string parseData(std::string const& s);
  7.  
  8. #endif

BaseData.cpp

  1. #include "BaseData.h"
  2.  
  3. static const std::string dataChars =
  4. "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  5. "abcdefghijklmnopqrstuvwxyz"
  6. "0123456789+/";
  7.  
  8. static inline bool isData(unsigned char c) {
  9. return (isalnum(c) || (c == '+') || (c == '/'));
  10. }
  11.  
  12. std::string saveData( char const* bytes_to_encode, unsigned int in_len) {
  13. std::string ret;
  14. int i = 0;
  15. int j = 0;
  16. unsigned char char_array_3[3];
  17. unsigned char char_array_4[4];
  18.  
  19. while (in_len--) {
  20. char_array_3[i++] = *(bytes_to_encode++);
  21. if (i == 3) {
  22. char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
  23. char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
  24. char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
  25. char_array_4[3] = char_array_3[2] & 0x3f;
  26.  
  27. for(i = 0; (i <4) ; i++)
  28. ret += dataChars[char_array_4[i]];
  29. i = 0;
  30. }
  31. }
  32.  
  33. if (i)
  34. {
  35. for(j = i; j < 3; j++)
  36. char_array_3[j] = '\0';
  37.  
  38. char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
  39. char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
  40. char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
  41. char_array_4[3] = char_array_3[2] & 0x3f;
  42.  
  43. for (j = 0; (j < i + 1); j++)
  44. ret += dataChars[char_array_4[j]];
  45.  
  46. while((i++ < 3))
  47. ret += '=';
  48.  
  49. }
  50. return ret;
  51.  
  52. }
  53.  
  54. std::string parseData(std::string const& encoded_string) {
  55. int in_len = encoded_string.size();
  56. int i = 0;
  57. int j = 0;
  58. int in_ = 0;
  59. unsigned char char_array_4[4], char_array_3[3];
  60. std::string ret;
  61.  
  62. while (in_len-- && ( encoded_string[in_] != '=') && isData(encoded_string[in_])) {
  63. char_array_4[i++] = encoded_string[in_]; in_++;
  64. if (i ==4) {
  65. for (i = 0; i <4; i++)
  66. char_array_4[i] = dataChars.find(char_array_4[i]);
  67.  
  68. char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
  69. char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
  70. char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
  71.  
  72. for (i = 0; (i < 3); i++)
  73. ret += char_array_3[i];
  74. i = 0;
  75. }
  76. }
  77.  
  78. if (i) {
  79. for (j = i; j <4; j++)
  80. char_array_4[j] = 0;
  81.  
  82. for (j = 0; j <4; j++)
  83. char_array_4[j] = dataChars.find(char_array_4[j]);
  84.  
  85. char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
  86. char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
  87. char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
  88.  
  89. for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
  90. }
  91.  
  92. return ret;
  93. }

此类中我们封装了两个重要的函数saveData和parseData,它们分别对数据进行编码和解码。

<1> std::string saveData(char const * ,unsigned int len)

作用:对字符串数据进行编码。

参数1:需要编码的目标字符串。

参数2:目标字符串长度。

<2> std::string parseData(std::string const & s)

作用:对字符串数据进行解码。

参数:需要解码的目标字符串。

三、项目实例

1、首先新建Cocos2D-X项目,取名为“MyDataSave02”,然后在项目中加入之前的BaseData类,最后在

HelloWorldScene.cpp文件的init函数中添加如下所示代码。

  1. bool HelloWorld::init()
  2. {
  3. bool bRet = false;
  4. do
  5. {
  6. CC_BREAK_IF(! CCLayer::init());
  7.  
  8. //需要存储的字符串
  9. string sValue = "Yangyu";
  10. //对存储的数据进行编码
  11. string saveBaseString = saveData(sValue.c_str(), sValue.length());
  12. //将得到编码后的数据进行存储
  13. CCUserDefault::sharedUserDefault()->setStringForKey("Base", saveBaseString);
  14. CCUserDefault::sharedUserDefault()->flush();
  15.  
  16. //从存储中获取编码的数据
  17. string loadBaseString = CCUserDefault::sharedUserDefault()->getStringForKey("Base");
  18. //对编码数据进行解码得到真实数据
  19. string trueValue = parseData(loadBaseString);
  20.  
  21. //---用以观察数据
  22. CCLabelTTF* label = CCLabelTTF::create("", "Helvetica", 20);
  23. label->setPosition(ccp(240,185));
  24. addChild(label);
  25. //编码之前的数据
  26. string logStr = "Before Encoding:";
  27. logStr+=sValue;
  28. //编码之后的数据
  29. logStr+=" After Encoding:";
  30. logStr+=saveBaseString;
  31. label->setString(logStr.c_str());
  32.  
  33. CCLabelTTF*label2 = CCLabelTTF::create("", "Helvetica", 20);
  34. label2->setPosition(ccp(240,140));
  35. addChild(label2);
  36. //解码之前的数据
  37. logStr = "Before Decode:";
  38. logStr+=loadBaseString;
  39. //解码之后的数据
  40. logStr+=" After Decode:";
  41. logStr+=trueValue;
  42. label2->setString(logStr.c_str());
  43.  
  44. bRet = true;
  45. } while (0);
  46.  
  47. return bRet;
  48. }

2、运行效果图

四、Base64编码解码工具

如果我们只是简单的将数据进行Base64编码,其实也是不安全的,对于稍微有些技术背景的人来说,对Base64解

码轻而易举!下图所示是我从网上随意使用了一个Base64解码工具,对刚编码的数据进行解码的例子。

在使用我提供的BaseData工具类时,我们需要在保存数据和读取数据时注意以下几点。

保存数据时:

<1> 当Base64对游戏数据进行编码后,不要着急进行存储,可以对编码后的字符串进行一些处理。例如在编码后的字符串中添加一

些无用字符、数字;或者在这个编码后的字符串进行位置调换操作等。

<2> 当对数据编码后的字符串进行处理后,在利用CCUserDefault进行保存。

读取数据时:

<1> 从存储文件中获取到数据后(已经做了处理的Base64编码字符串),首先对获取的数据进行反操作(按照存储

之前对编码字符串的操作进行反操作)。

<2> 反操作得到正确的Base64编码字符串后再进行Base64解码,以得到真实数据。

这里一来,除非破解者知道你做处理的过程,或者有你的源码,否则会很难破解你的数据。

源码下载地址

【Cocos2d-X开发学习笔记】第30期:游戏中数据的存储(下)的更多相关文章

  1. 【Cocos2d-X开发学习笔记】第29期:游戏中数据的存储(上)

    本系列学习教程使用的是cocos2d-x-2.1.4(最新版为3.0alpha0-pre) ,PC开发环境Windows7,C++开发环境VS2010 一般游戏中都需要记录玩家数据,便于玩家下次登录时 ...

  2. 【Android开发学习笔记】【第八课】五大布局-下

    概念 五大布局上一篇文章已经介绍了 LinearLayout RelativeLayout 这一篇我们介绍剩下的三种布局 FrameLayout 五种布局中最佳单的一种布局.在这个布局在整个界面被当成 ...

  3. 基于.NET的CAD二次开发学习笔记二:AutoCAD .NET中的对象

    1.CAD对象:一个CAD文件(DWG文件)即对应一个数据库,数据库中的所有组成部分,看的见(包括点.多段线.文字.圆等)和看不见(图层.线型.颜色等)的都是对象,数据库本身也是一个对象. 直线.圆弧 ...

  4. Rest API 开发 学习笔记(转)

    Rest API 开发 学习笔记 概述 REST 从资源的角度来观察整个网络,分布在各处的资源由URI确定,而客户端的应用通过URI来获取资源的表示方式.获得这些表徵致使这些应用程序转变了其状态.随着 ...

  5. Chrome扩展,应用开发学习笔记之2---恶搞百度一下

    Chrome扩展,应用开发学习笔记之2 恶搞百度一下 前面我们介绍了一个最简单的chrome扩展时钟,如今我来介绍一下一个恶搞百度一下的chrome扩展程序. 前面说过,manifest.json文件 ...

  6. 【前端】移动端Web开发学习笔记【2】 & flex布局

    上一篇:移动端Web开发学习笔记[1] meta标签 width设置的是layout viewport 的宽度 initial-scale=1.0 自带 width=device-width 最佳实践 ...

  7. 【前端】移动端Web开发学习笔记【1】

    下一篇:移动端Web开发学习笔记[2] Part 1: 两篇重要的博客 有两篇翻译过来的博客值得一看: 两个viewport的故事(第一部分) 两个viewport的故事(第二部分) 这两篇博客探讨了 ...

  8. 驱动开发学习笔记. 0.07 Uboot链接地址 加载地址 和 链接脚本地址

    驱动开发学习笔记. 0.07 Uboot链接地址 加载地址 和 链接脚本地址 最近重新看了乾龙_Heron的<ARM 上电启动及 Uboot 代码分析>(下简称<代码分析>) ...

  9. android开发学习笔记000

    使用书籍:<疯狂android讲义>——李刚著,2011年7月出版 虽然现在已2014,可我挑来跳去,还是以这本书开始我的android之旅吧. “疯狂源自梦想,技术成就辉煌.” 让我这个 ...

随机推荐

  1. 终于懂了:WM_PAINT中应该用BeginPaint与EndPaint这两个api,它们的功能正是使无效区域恢复(所以WM_PAINT里即使什么都不做,也必须写上BeginPaint与EndPaint)——Delphi里WM_PAINT消息的三个走向都做到了这一点 good

    程序本来是想实现鼠标单击改变背景颜色.可是,程序运行时,为什么没有任何消息触发,背景颜色就一直不断的改变了?WM_PAINT怎么被触发的 #include <windows.h> #inc ...

  2. oracle忘记密码,修改密码,解锁

    忘记密码修改密码: alter user system identified by values abc111; 修改后的用户名system,密码abc111. 解锁: cmd->输入 :sql ...

  3. Selenium 出现: Caused by: java.lang.ClassNotFoundException: org.w3c.dom.ElementTraversal

    webDriver 运行的时候出现: Caused by: java.lang.ClassNotFoundException: org.w3c.dom.ElementTraversal 解决办法: 只 ...

  4. 新发现的Cyberduck(映射网盘)和zsuncloud(硬件产品很新潮),群辉nas的确好用(购买链接)

    https://cyberduck.io/?l=en http://www.zsuncloud.com/ 群辉nas的确好用啊在哪里可以买到?官网 淘宝也可以自己做黑群晖 先用xpenoboot is ...

  5. SQL Server Join方式

    原文:SQL Server Join方式 0.参考文献 Microsoft SQL Server企业级平台管理实践 看懂SqlServer查询计划 1.测试数据准备 参考:Sql Server中的表访 ...

  6. Control.Invoke和Control.BeginInvoke

    问题的引入 下面有个简单的demo,大家一看代码就知道效果如何示例.我新建一个winform的程序,然后写入了如下代码: using System; using System.Windows.Form ...

  7. SQL逆向工程

    话说有个现成的SQL数据库,四十来张表,每张表多的几十的字段,少的十几个字段.老板说为了下一步大家好好利用这个数据库中的数据,让你研究一下该数据库中的所有的表和字段之间的联系.这是一个什么性质的工作, ...

  8. CImageList类Create函数参数解析

    前面提到了CImageList类的Create(...)函数,虽然MSDN上已经有所解释,但仍有网友问到参数的具体含义,下面就我的理解,对参数进行一次轻量级的剖析 函数原型(其他重载函数请参看msdn ...

  9. [置顶] android之Notification版本兼容性问题

    首先先来创建一个notification提示 //概要 String tickerText = context.getResources().getText(R.string.app_name).to ...

  10. ListView+CheckBox两种解决方式及原因分析

    近期在用ListView+CheckBox搞一个item选中的项目,我将CheckBox的focus设置为false,另我大喜的是,CheckBox居然能够选中(窃喜中),这么简单就搞定了,由于数据量 ...