cocos lua游戏过程记录(复盘)
来源:互联网 发布:淘宝也有货到付款的吗 编辑:程序博客网 时间:2024/04/29 12:27
一、复盘原理
我们都知道所谓回放游戏过程,只不过把游戏消息存储下来,在执行一遍。
我的复盘原理是这样实现(麻将):
1)游戏结束,服务器会发送这局执行的所有消息。
2)客户端接受到消息,通过使用lua绑定C++方法读出数据(这也是第二点要讲解的)
3)lua读写文件,把读出的数据以二进制形式存储到本地
4)从本地读出二进制文件,解析内容,得到消息和数据,从而实现回放。
二、读取数据
对于一般的网游公司,都有自己的一套网络通讯代码。
1)一般都是服务器定义一个结构体
2)发送给客户端
3)客户端接受数据,解析数据执行,并返回结果给服务器。
4)循环1-3。。。
因为从服务器接受过来的数据是占据连续的一片内存空间,这有什么用呢?
用处就是:我们可以通过按字节移位的方式来读取数据了(按一字节对齐)。
举个列子:
struct AAA{DWORD a1;WORDa2;};服务器发来的结果体是这样的,那我们应该如何读取a1,a2中的数据呢?
DWORD MsgClass::readDWORD(){ WORD value = 0; if (m_Pos + 4 <= m_Len) { WORD t = 0;memcpy(&t,(const BYTE*)m_Buffer + m_Pos,4); value = t; } m_Pos += 4; return value;}
WORD MsgClass::readWORD(){ WORD value = 0; if (m_Pos + 2 <= m_Len) { WORD t = 0;memcpy(&t,(const BYTE*)m_Buffer + m_Pos,2); value = t; } m_Pos += 2; return value;}按照上面写的代码,绑定解析类MsgClass来解析结构体,这就是按字节移位的方式来读取数据了。
我们就能在lua中使用绑定方法来解析数据:
local a1 = readDWORD()
local a2 = readWORD()
三、存储文件
从第二点可以知道,不管传过来的数据如何,都是可以解析出来的。
那下面有2种形式来存储了:table 和 二进制存储
1、table 存储:顾名思义把传过来的数据以table形式存储
网上有存储脚本,就不列出了,最后存储的形式:(大致相同)
require "SaveTableToFile"local ex = {}ex.year = 2017ex.month = 1ex.day = 4ex.name = "msdb1989"table.save(ex, "file.dat")----------------------------------------return {-- Table: {1}{ ["day"]=4, ["year"]=2017, ["month"]=1, ["name"]="msdb1989",},}存储形式是个表, 读出来也是一个表。
存储方法的优点:一目了然,存储的数据很明确。
存储方法的缺点:增加了存储文件的大小,io操作效率低,对于大型数据不适合。
2、二进制存储:这个其实是我自己定义的(不好意思),就是服务器传来的数据,不做任何处理,直接存储字节流(换句话说就是来什么存什么)。
例如:
struct CMD_S_Task{DWORDdwUserID;WORDwKindID;WORD wServerID;............charszNickName[MAX_LEN];};对于这样很大的结果体,或者数据很多时,用table来存储性能就很低了。
做复盘的时候,有个复盘头和复盘数据。复盘头是记录玩家信息,复盘数据则是记录玩家操作,而我一开始用table来实现,发现复盘数据很多的情况下,根本来不及存储,所以我才改为二级制存储。
1)保存文件
那怎么做到把发来的数据一下全部存储呢。
/// 读取一个void*数据char* MsgClass::readvoids(int length) {if (length < 0) {return "";}char* value = new char[length + 1];memset(value, 0, sizeof(char)*(length + 1));if (m_Pos + 1 <= m_Len) {memcpy(value, (const char*)m_Buffer + m_Pos, length);}m_Pos += length;return value;}要读取这个数据包内容,self.m_AryReplayBuffer = msgclass:readvoids(512) 这样就可以了,512表示字节为这个数据包大小,目前最大支持20K,当然还能更大。
这样存下来就是二进制文件了。
2)读取文件
//写入voidvoid MsgClass::WritevoidToBuffers(const char* ch, int len) {memcpy((char*)&m_socketBuffers[m_len], ch, len);m_len += len;}
file = io.open("123.dat", "rb")if file == nil then returnendResetBuffers()WritevoidToBuffers(file:read(512), 512)SendForMessage("主消息", "子消息")这样就能读取保存在123.dat里的512字节,然后把消息派发下去,就能模拟服务器发来的消息,这样就能实现复盘了。
四、后续工作
当然还有很多工作没有处理
比如:回退,前进,最开始,结束等等。
这些其实,只不过是发不同的消息而已。
例如:上面例子512位头数据,那么512之后就是游戏开始消息了,开始消息发完就是第二个游戏消息了,既然知道所有数据,那前后,开始结束也就知道了。
- cocos lua游戏过程记录(复盘)
- cocos-lua问题记录
- Cocos Lua入坑过程
- Cocos、Lua游戏内存释放之我见
- 如何使用Cocos Code IDE调试Lua开发的游戏
- cocos-lua 手游之游戏新手引导
- (cocos笔记) cocos lua 粒子特效试用
- 学习记录:cocos 2d-x 飞机游戏开发
- Cocos游戏场景切换(C++)
- cocos lua scheduler
- cocos lua学习笔记
- cocos-lua Test详解
- cocos-lua-Nodex
- cocos-lua-spriteex
- cocos-,lua- tolua.cast
- cocos-lua-通知节点
- cocos-lua 表
- lua cocos class方法
- 手把手带你实现Android增量更新
- 非常简单而又非常完整的R语言主成分分析实例
- LESS知识学习
- 数据驱动编程
- hdu4280 Island Transport(最大流入门)
- cocos lua游戏过程记录(复盘)
- selenium结合Sikuli-Script使用
- 养成这五个习惯,成为资深设计师(四)
- java smtp 发送邮件的例子
- 安卓SoundPool只能发出一次声音,或者没有声音
- 可扩展Web架构与分布式系统
- 循环神经网络(RNN, Recurrent Neural Networks)介绍
- VS 文件夹太大,删掉*.sdf 和 *.ipch
- Scala 补充