《棋牌游戏服务器》玩法编程范式建议
承接游戏服务器的架构介绍,本篇试图规范玩法模块的编程模式,提高代码质量。
在前面的架构种,诸如GameThread、StateMachine这样的类很少需要继承修改;开发的重点在其他类上,这个范式的核心在于明确这些类的职责,以及经验教训总结。
1、GameTable
GameTable的职责是在内存中维护“”游戏桌子“的“相对静态“的”数据状态,包括房间的配置数据以及桌子内的玩家数据。
table内部原则上不操作数据库以及redis,但是在玩家入桌和离桌的时候例外,需要在redis里面记录记录一下玩家的坐标(服务器+房间)。
table内的房间配置数据在游戏运行的过程中,有被修改的可能性,所以建议每一局游戏开始的时候刷新一下(在一局过程中刷新是不合适的)。一般房间配置数据来自配置文件,关于配置文件的运作机制,这里不赘述。
一旦配置数据被修改,就涉及和客户端的同步,这个也要看具体情况而定(数据量、重要程度、易变性),有些配置字段不同步也没问题,有些可以在每一局开始时通过消息推送给客户端。
2、GameRound
round是游戏过程中动态数据,维护每一局游戏的过程状态,比如用户下了多少注,发了什么牌;总之,仅在一局内有效的数据都放入这个结构;
一局开始时,不要复用上一局的round,重新创建一个round实例,可以避免很多问题。
3、GameState(状态机状态)
一般玩法会有若干状态,有以下几点建议:
1)状态基类:每个玩法设计一个状态基类,一来实现一些公共的功能函数;二来实现消息的分发,子状态如果要处理某个消息,重写对应消息处理函数即可。
2)有一个“等待开局”状态:有些玩法从需求上看,似乎不需要这个状态;也建议保留这个状态,总有一些开局前检查的工作要做;这个状态在时间上可以非常短,完成基本的检查之后就切走,对客户端透明。
3)MessageProcessor(消息处理器):state将消息处理委托给这个类,避免将state的代码搞得特别臃肿。
4)关于state和messageprocessor的分工,凡是涉及状态切换、桌子销毁等核心流程的环节,state来处理,不要放到processor里面;processor只处理来自玩家的消息,并做出响应,点到即止,方便不同的State子类调用。
某些客户端消息的处理,会涉及以上两个部分的功能,先由processor处理完消息,state再检查处理结果,以决定是否需要做状态切换。
4、MessageProcessor
1)消息处理器的首先要保持简洁,如上面3.4所说,点到即止,不要越权。
2)另外一定要对参数合法性(下注的合法性,额度校验等),table和round的当前状态做检查,先排除异常情况、不满足执行条件的情况。
3)不要假定消息处理总会成功,比如用户下注,可能由于没有足够的金币,要返回失败标记给GameState,后者需要依据这个结果来进一步决定状态机的迁移方向。
总之这块特别要注意异常状态检查,以及潜在外挂的防御。