详解房卡麻将分析系列 "牌局回放" 之 播放处理
作者:lqh 发布时间:2022-12-26 08:54:27
详解房卡麻将分析系列 "牌局回放" 之 播放处理
昨天红孩儿给大伙讲了讲”牌局回放“的数据记录处理,有了数据的存储,下面就是数据的显示了。
实话讲,好久没用过 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++;
...
}
于是,一场精彩的牌局就被完完整整的回放了。
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
来源:http://blog.csdn.net/honghaier/article/details/60756241
猜你喜欢
- 一. SpringBoot中实现Session共享1. 创建web项目我们按照之前的经验,创建一个web程序,并将之改造成Spring Bo
- BeanFactory接口:IoC容器的顶级接口,是IoC容器的最基础实现,也是访问Spring容器的根接口,负责对bean的创建,访问等工
- 工程加入依赖:<dependency><groupId>org.apache.pdfbox</groupId&
- 前言:本文主要讲解以c语言编写猜数字游戏,目的是介绍C语言中的循环和分支的具体用法。一:猜数字游戏基本介绍&对程序预期.猜数字游戏,
- 这篇文章主要介绍了Java线程状态运行原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参
- 方法如下:声明一个事件: Num_DiscountAmount.MouseWheel +=n
- 在同一个类中: 对于静态方法,其他的静态或非静态方法都可以直接调用它。而对于非静态方法,其他的非静态方法是可以直接调用它的。但是其他静态方法
- 使用WebSocketSharp自定义实现Web服务时,无法解析multipart/form-data请求的数据。通过查找资料,采用以下方式
- 前言最近项目targetSdkVersion升级到了26,出现很多问题趟了很多坑,其中就包括本篇的需要解决的问题:全局dialog 不显示。
- 本文实例讲述了android编程实现图片库的封装方法。分享给大家供大家参考,具体如下:大家在做安卓应用的时候 经常要从网络中获取图片 都是通
- 1. 效果图展示2. 工程目录结构注意: webapp下的resources目录放置easyui和js(jQuery文件是另外的) 
- 在jdk1.4中提出的技术,非阻塞IO,采用的是基于事件处理方式。传统的io技术为阻塞的,比如读一个文件,惹read方法是阻塞的,直到有数据
- Android WebView的使用方法 Android app打开H5页一般要实现如下需求:1、打开指定url网页
- public interface ArraySQL 类型 ARRAY 在 java 编程语言中的映射关系。默认情况下,Array 值是对 S
- System.Web.Caching.Cache Insert和Add方法的区别Add()object Add(string key, ob
- Android中的线程池ThreadPoolExecutor解决了单线程下载数据的效率慢和线程阻塞的的问题,它的应用也是优化实现的方式。所以
- 问题描述我在接受 mq 消息的时候,需要做一个重试次数限制,如果超过 maxNum 就发邮件告警,不再重试。所以我需要对 consumer
- 当数据库中数据条数过多时,一个页面就不能显示,这是要设置分页查询,首先要使用的是数据库sql语句的limit条件实现分组查询sql语句大概形
- 这里我记录一个比较简单方便操作的JAVA上传文件图片到服务器并且保存,具体内容如下首先是页面html的 我这是提交一
- 很多学习Android程序设计的人都会发现每个人对代码的写法都有不同的偏好,比较明显的就是对控件响应事件的写法的不同。因此本文就把这些写法总