详解房卡麻将分析系列 "牌局回放" 之 播放处理

详解房卡麻将分析系列 "牌局回放" 之 播放处理

昨天红孩儿给大伙讲了讲”牌局回放“的数据记录处理,有了数据的存储,下面就是数据的显示了。

实话讲,好久没用过 SQL Server 来做数据库了, 网狐的服务器是基于WIN,IOCP,  SQL Server 这套路子。配置好后,可以在QPTreasureDB数据库中看到三个牌局相关的表。

其中dbo.PrivateGameRecord是存储当前游戏的房间及玩家,最终胜负信息的。

dbo.PrivateGameRecordChild是存储当前游戏的每一局的牌局回放,也就是咱们上篇文中所讲述的每一场牌局详情和操作数据。

dbo.PrivateGameRecordUserRecordID是记录ID与玩家ID的对应关系。

我们打开dbo.PrivateGameRecord,可以看到有一个属性字段UserData存储着一堆二进制数据。也就是我们上节中通过Stream_VALUE来将结构数据填充为字节流后存进来的。

当客户端在进入战绩界面时,会向登录服务器发送SUB_GP_GAME_RECORD_LIST消息,请求当前玩家的所有参与过的房间据,也就是dbo.PrivateGameRecord中与玩家相关的数据列表。这个可以在CGPGameRecord.cpp的CB_GetGameRecordList函数中看到。

在登录服务器的AttemperEngineSink.cpp中,我们可以看到登录服务器会在收到消息后转发数据库请求,数据库再通过存储过程拉数据出来。之后返回给客户端。

客户端收到后通过StreamValue将数据流解析到结构tagPrivateRandTotalRecord中显示出来。

当玩家看到这条信息后,如果想查看每一局的战局,会再点击"详情"按钮,这时客户端会向登录服务器再次发送SUB_GP_GAME_RECORD_CHILD消息,同上面的流程大体一致,经过这样一个来回,客户端会得到房间中每局的详细数据,收到后通过StreamValue将数据流解析到结构tagPrivateRandRecordChild中显示出来。

玩家现在能看到每一局的详情了,他如果想看牌局回放,会再调用GameScene的StartRecord(datastream kDataStream)来将tagPrivateRandRecordChild中的数据流转化为当前玩家牌局信息和操作信息。之后显示游戏场景和回放操作按钮菜单。有了具体的数据,通过按钮菜单来控制播放的速度,上一步,下一步并不复杂。在GameScene的NextRecordAction函数中,我们可以看到如何根据当前的操作类型来进行相应的操作复现玩家的出牌和操作。

void GameScence::NextRecordAction() { ... GameRecordOperateResult& kAction = m_pGameRecord->kAction[m_iActRecordIdex]; int iChairID = (m_wRecordSelfChairID-kAction.wOperateUser+MAX_PLAYER)%MAX_PLAYER; int iProvideUser = (m_wRecordSelfChairID-kAction.wProvideUser+MAX_PLAYER)%MAX_PLAYER; if (kAction.cbActionType == GameRecordOperateResult::TYPE_OperateResult) { Player* pPlayer = m_pPlayer[iChairID]; CMD_S_OperateResult kTempCMD; kTempCMD.cbOperateCard = kAction.cbOperateCard; kTempCMD.cbOperateCode = kAction.cbOperateCode; kTempCMD.wOperateUser = kAction.wOperateUser; kTempCMD.wProvideUser = kAction.wProvideUser; Player* pProvidePlayer = m_pPlayer[iProvideUser]; if (pProvidePlayer &&(kAction.cbOperateCode == WIK_PENG || kAction.cbOperateCode == WIK_LEFT || kAction.cbOperateCode == WIK_CENTER || kAction.cbOperateCode == WIK_RIGHT || (kAction.cbOperateCode == WIK_GANG && kAction.wOperateUser != kAction.wProvideUser ))) { pProvidePlayer->removeHandOutCard(kAction.cbOperateCard); pProvidePlayer->setActOutCard(-1); //设置当前玩家 for (int i = 0; i<MAX_PLAYER; i++) { m_pPlayer[i]->stopAniCurrPlayer(); } pProvidePlayer->runAniCurrPlayer(); } pPlayer->setOperateResoult(&kTempCMD); pPlayer->showCard(); } if (kAction.cbActionType == GameRecordOperateResult::TYPE_SendCard) { XPlayer* pPlayer = m_pPlayer[iChairID]; if (kAction.cbOperateCard != 0) { pPlayer->addNewInCard(kAction.cbOperateCard); } pPlayer->showCard(); //设置当前玩家 for (int i = 0; i<MAX_PLAYER; i++) { m_pPlayer[i]->stopAniCurrPlayer(); } pPlayer->runAniCurrPlayer(); } if (kAction.cbActionType == GameRecordOperateResult::TYPE_OutCard) { Player* pPlayer = m_pPlayer[iChairID]; for (int i = 0;i<MAX_PLAYER;i++) { m_pPlayer[i]->setActOutCard(-1); } pPlayer->sendOutCard(kAction.cbOperateCard); pPlayer->showCard(); } if (kAction.cbActionType == GameRecordOperateResult::TYPE_ChiHu) { Player* pPlayer = m_pPlayer[iChairID]; for (int i = 0;i<MAX_PLAYER;i++) { m_pPlayer[i]->setActOutCard(-1); } pPlayer->setChiHuCard(kAction.cbOperateCard); pPlayer->showEffect("Hu"); if (kAction.wOperateUser != kAction.wProvideUser) { XZDDPlayer* pDestPlayer = m_pPlayer[iChairID]; pPlayer->showHandCard(); pPlayer->showStatusImagic("Hu"); pDestPlayer->runAniHu(); } else { pPlayer->showStatusImagic("ZiMo"); pPlayer->runAniZiMo(); } pPlayer->showCard(); } m_iActRecordIdex++; ... }

于是,一场精彩的牌局就被完完整整的回放了。

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

时间: 2024-11-08 21:44:18

详解房卡麻将分析系列 "牌局回放" 之 播放处理的相关文章

房卡麻将分析系列 "牌局回放" 之 数据设计详解及实例

房卡麻将分析系列 "牌局回放" 之 数据设计 最近几个月,"房卡"棋牌游戏成为了资本追逐的热点,基于微信的广大用户和社交属性,"房卡"棋牌发展迅速.红孩儿团队因为之前几年有过相关项目的经验积累,鉴于未来广阔的地方棋牌市场和"开发间"机制的发展前景,也开始转向基于"开房间"棋牌游戏的项目开发中.为了更好的与开发者进行交流学习,特开设"房卡麻将游戏分析系列". 红孩儿团队研发的"大

jQuery中deferred对象详解及源码分析

jQuery的deferred对象使用详解 jQuery的开发速度很快,几乎每半年一个大版本,每两个月一个小版本.每个版本都会引入一些新功能.今天我想介绍的,就是从jQuery 1.5.0版本开始引入的一个新功能--deferred对象.这个功能很重要,未来将成为jQuery的核心方法,它彻底改变了如何在jQuery中使用ajax.为了实现它,jQuery的全部ajax代码都被改写了.但是,它比较抽象,初学者很难掌握,网上的教程也不多.所以,我把自己的学习笔记整理出来了,希望对大家有用. 本文不

详解用ELK来分析Nginx服务器日志的方法_nginx

所有ELK的安装包都可以去官网下载,虽然速度稍慢,但还可以接受,官网地址:https://www.elastic.co/ logstash 在Logstash1.5.1版本,pattern的目录已经发生改变,存储在/logstash/vendor/bundle/jruby/1.9/gems/logstash-patterns-core-0.1.10/目录下,但是好在配置引用的时候是可以对patterns的目录进行配置的,所以本人在Logstash的根目录下新建了一个patterns目录.而配置目

详解Mysql中的JSON系列操作函数_Mysql

前言 JSON是一种轻量级的数据交换格式,采用了独立于语言的文本格式,类似XML,但是比XML简单,易读并且易编写.对机器来说易于解析和生成,并且会减少网络带宽的传输. JSON的格式非常简单:名称/键值.之前MySQL版本里面要实现这样的存储,要么用VARCHAR要么用TEXT大文本. MySQL5.7发布后,专门设计了JSON数据类型以及关于这种类型的检索以及其他函数解析. 下面一起来实际操作一下. 创建带有 JSON 字段的表 比如一个'文章'表,字段包括 id.标题 title.标签 t

Linux系统调用详解(实现机制分析)--linux内核剖析(六)

系统调用概述 计算机系统的各种硬件资源是有限的,在现代多任务操作系统上同时运行的多个进程都需要访问这些资源,为了更好的管理这些资源进程是不允许直接操作的,所有对这些资源的访问都必须有操作系统控制.也就是说操作系统是使用这些资源的唯一入口,而这个入口就是操作系统提供的系统调用(System Call).在linux中系统调用是用户空间访问内核的唯一手段,除异常和陷入外,他们是内核唯一的合法入口. 一般情况下应用程序通过应用编程接口API,而不是直接通过系统调用来编程.在Unix世界,最流行的API

详解Windows注册表分析取证

大多数都知道windows系统中有个叫注册表的东西,但却很少有人会去深入的了解它的作用以及如何对它进行操作.然而对于计算机取证人员来说注册表无疑是块巨大的宝藏.通过注册表取证人员能分析出系统发生了什么,发生的时间以及如何发生的等.在本文中我将为大家详细介绍Windows注册表的工作原理,以及如何对收集用户留下的各类指纹信息. 什么是注册表? 注册表是用于存储Windows系统用户,硬件和软件的存储配置信息的数据库.虽然注册表是为了配置系统而设计的,但它可以跟踪用户的活动,连接到系统的设备,什么时

RHCE学习&lt;6&gt;Apache、Nginx详解和AWStats日志分析

一.Apache服务 Apache是Apache软件基金会的一个开放源码的网页服务器,是世界使用最广泛的Web服务端之一,译为阿帕奇:Apache具有优秀的性能,稳定性,是通过加载模块来提供各种功能. 1.主配置httpd.conf 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ServerRoot     #服务目录 ServerAdmin    #管理员邮箱 user           #运行服务的用户身份 group        

Epoll详解及源码分析【转】

  转自:http://blog.csdn.net/chen19870707/article/details/42525887 版权声明:本文为博主原创文章,未经博主允许不得转载.   目录(?)[-]   什么是epoll   Apache模型Process Per Connection简称PPC 和 TPCThread Per Connection模型 select模型 poll模型 epoll模型 Epoll API int epoll_createint size int epoll_c

Ajax详解及其案例分析_AJAX相关

1 获得Ajax对象 1.1 问题 如何获得XmlHttpRequest对象. 1.2 方案 区分浏览器,使用不同的获取方式. 1.3 步骤 步骤一: 新建ajax01.html页面 新建一个Web工程,在WebRoot下新建ajax01.html页面.在<script>标记内编写JavaScript代码实现获取Ajax对象. <script type="text/javascript"> /*获取Ajax对象*/ function getXhr(){ var