《棋牌游戏服务器》机器人设计
机器人的架构基于前面的游戏服务器架构设计展开,可以视为后者的附属设计。
1、设计目标
1)机器人与游戏主流程耦合性尽量少,机器人即使有问题,不影响主流程;
2)机器人由桌子线程驱动,不单独开新的线程
机器人和游戏逻辑是在一个进程里面运行的,所以机器人直接对table进行访问可以简化系统的设计,但原则上,机器人只能对table进行只读操作。
2、消息机制
为了达成目标1),决定机器人和游戏table之间使用消息通讯,把机器人当做客户端,tabe当做服务端。
于是乎,定义了两类消息,一类是RobotClientMessage,代表机器人发给table的消息;一类是RobotServerMessage,代表table发给机器人的消息。
消息的处理全部异步化,降低相互影响。
由于有了消息机制,达成目标2)就比较方面了,只要将消息push进table线程,table线程做分发即可。
对于RobotClientMessage,table线程交由table的状态机处理,和处理来自客户端的消息类似;对于RobotServerMessage消息,table线程交由robot实例处理;
这一步骤在game-core库里面支持,game-core还增加了对robot时钟的支持。
3、机器人的分配和销毁
我们的目标是降低机器人和table之间的耦合性,所以尽量不让table对机器人进行区别对待,同时table也不需要维护机器人列表。
有一个叫RobotManager的类来提供机器人的分配、查找、销毁功能;
1)分配
RobotManager分配了机器人实例以后,会在redis里面加锁,然后会周期性地扫描机器人是否仍然被占用,以刷新锁。
2)销毁
当机器人离开table的时候(是现在捕鱼的table基类中处理),就是机器人销毁的时候,此时RobotManager会在内存中删除机器人并删掉redis锁。
3)查找
RobotManager里面会维护该服务器所有存活的机器人,所以很容器查找某个桌子有哪些机器人。
4、机器人的状态机
机器人的行为可能比较复杂,所以也用状态机的形式来实现,这和table的状态机如出一辙,这里不做赘述。
有所区别的是,捕鱼的机器人基类,预置了几个状态,比如RobotJoinState和RobotLeaveState,分别代表机器人入桌状态和离桌状态。
有些情况下,机器人可能不需要这两个状态,比如一些匹配式的玩法,不需要入桌流程,忽略即可。
5、核心类介绍
GameRobotBase,机器人核心基类,在game-core库里面,具体玩法要继承这个类。
方法 |
含义 |
---|---|
GameRobotBase(PlayerInfo) |
构造函数,所有机器人必须有仅且有一个该签名的构造函数 |
initialize(gameTable) |
初始化,子类一般要重写,由于机器人在创建的时候,可能还没有桌子,所以初始化要单独一个方法 |
addState(RobotState<RobotType> state) |
增加一个状态,一般在子类的构造函数或initialize中调用 |
setExceptionStateId(int exceptionStateId) |
设定异常状态,机器人逻辑发生异常时进入,捕鱼里已经预置为RobotLeaveState |
start(int stateId, Object param) |
机器人启动状态机,只有调用了这个方法,机器人才会开始工作 |
changeState(int initStateId, Object param) | 状态机切换状态 |
addTimer(int timerType, long delayMillis, Object param) | 设置一个定时器 |
sendClientMessage(int msg, Object param) |
发送消息给桌子 |
acceptServerMessage(int msg, Object param) |
接收消息,当外部逻辑给机器人发消息时,调用这个方法 |
RobotState, 机器人状态类
方法 |
含义 |
---|---|
enter(RobotType e,Object param); |
状态进入回调 |
handleTimerEvent(RobotType e ,int timerType,Object param) |
处理时钟事件,参见GameRobotBase.addTimer |
handleServerMessage(RobotType e, RobotServerMessage t) |
处理接收的消息,参见GameRobotBase.acceptServerMessage
|
AbstractTableState(table状态机的状态基类),用以支持机器人的方法:
方法 | 含义 |
---|---|
handleRobotClientMessage |
处理机器人发送的消息,参见GameRobotBase.
sendClientMessage |
6、关于GameRobotBase.start方法
机器人在完成初始化之后,如果不调用start方法是不会运作的,但是不同的玩法start的调用时机有所不同。
1)一般的入桌子式的玩法,机器人分配好了就立即初始化,然后立即start,然后进入RobotJoinState;
2)匹配式的玩法,比如斗地主,在匹配过程中需要创建机器人,但此时对应的GameTable还没有,等匹配成功之后,table创建好,才能完成初始化,然后再start;
原则是机器人可以提前创建,有了table就初始化,游戏逻辑需要这个机器人开始运作的时候就调用start。
3)机器人创建好了不能长时间不用(暂定5分钟),RobotManager里面有自动回收逻辑,如果发现一个机器人长时间不活动,会认为这是一个僵尸而回收掉。