[toc]
Ratel 是一个可以在命令行中玩斗地主的项目,可以使用小巧的jar包在拥有JVM环境的终端中进行游戏,同时支持人人对战和人机对战两种模式,丰富你的空闲时间!
Ratel使用Java语言开发,Netty 4.x网络框架搭配protobuf数据协议,可以支持多客户端同时游戏。
Ratel面向响应式架构,通过事件码进行通讯,对于Ratel-Client,支持跨平台扩展,换一种说法,任何后端语言都可以开发Ratel-Client!
在开发Ratel-Client前应该知道:
- Ratel Server-Client交互网络协议为
TCP/IP
。 - Ratel Server-Client交互数据协议为protobuf。
- Ratel以事件为驱动,在Client将各个环节串联起来。
- Ratel所有的文案都由Client显示。
我们可以使用任何后端语言就重写Ratel客户端,Ratel默认的客户端的由Java语言编写,如果你想使用其他语言重写,以下是我们推荐的一种架构:
这种架构对于事件的处理非常友好,你可以设计一个抽象的Event-Listener
接口,然后开发不同的实现去处理不同CODE
对应的响应数据,例如一个而简单的例子——Poker的显示,以下是我们的处理流程的伪代码:
1、对服务端响应数据解码 ->
decode(msg)
2、解码后的数据 ->
ClientData{
String code;
String data;
}
3、通过code寻找对应的EventListener ->
showPokersEventListener = Map<code, EventListener>.get(code)
4、处理响应数据 ->
showPokersEventListener.call(server, data){
show(data);
server.write(msg);
}
以上只是简单的Server-Client
的交互流程,有时候可能会出现Client-Client
的场景,例如客户端的选项面板的显示,在我们从A层切换到B层,再从B层返回到A层,这时就需要做Client-Client
的交互。
当然,大多数的交互重点集中在Server-Client
,而另一方面,客户端大多都是在处理并显示服务端响应的数据,对于真正的业务交互很少,这对于客户端来说,只要将事件绝对的丰富,那么客户端的流程就会绝对的灵活。因此,Ratel的客户端响应事件相比于服务端的响应事件数量多了几倍有余,所以这对于客户端的架构要求就是要有足够的灵活性,能够支持以下两个业务流:
- Server-Client-Server
- Server-Client-Client-Server
之后,我们进入下一步!
对于客户端和服务端交互的数据,为了承载,我们需要设计两个类去存放编解码后的数据,值得一提的是,客户端和服务端的数据结构一样,都由CODE
、DATA
和INFO
三个字段组成:
- CODE - 对应的事件
- DATA - 传递的数据
- INFO - 信息(暂时用不到)
我们的编解码方式为Protobuf
序列化,参考文件请看这里。
在我们做好对接的准备工作之后,可以通过以下协议文档开始实现客户端的业务!
CODE
- CODE_CLIENT_CONNECTTYPE
- TEXTDATA
- 客户端被分配的ID
CODE
- CODE_CLIENT_EXITTYPE
- JSONDATA
- 如下
字段名 | 含义 |
---|---|
roomId | 房间ID |
exitClientId | 退出者ID |
exitClientNickname | 退出者昵称 |
参考数据
{"roomId":14,"exitClientId":64330,"exitClientNickname":"nico"}
CODE
- CODE_CLIENT_KICKTYPE
- TextDATA
- NULL
CODE
- CODE_CLIENT_NICKNAME_SETTYPE
- JSONDATA
- 如下
字段名 | 含义 |
---|---|
invalidLength | 有效长度,当设置昵称超过10个字节会返回此字段 |
参考数据:
{"invalidLength":10}
CODE
- CODE_GAME_LANDLORD_CONFIRMTYPE
- JSONDATA
- 如下
字段名 | 含义 |
---|---|
roomId | 房间ID |
roomOwner | 房间所有者昵称 |
roomClientCount | 房间人数 |
landlordNickname | 地主昵称 |
landlordId | 地主ID |
additionalPokers | 额外的三张牌 |
参考数据:
{"roomId":14,"roomOwner":"nico","roomClientCount":3,"landlordNickname":"robot_2","landlordId":-8,"additionalPokers":[{"level":"LEVEL_5","type":"DIAMOND"},{"level":"LEVEL_6","type":"CLUB"},{"level":"LEVEL_A","type":"DIAMOND"}]}
CODE
- CODE_GAME_LANDLORD_CYCLETYPE
- TEXTDATA
- NULL
TIP:该事件触发后会连续触发重新游戏事件
CODE
- CODE_GAME_LANDLORD_ELECTTYPE
- JSONDATA
- 如下
字段名 | 含义 |
---|---|
roomId | 房间ID |
roomOwner | 房间所有者昵称 |
roomClientCount | 房间人数 |
preClientNickname | 上一个客户端的昵称 |
nextClientNickname | 下一个客户端的昵称 |
nextClientId | 下一个客户端的ID |
参考数据:
{"roomId":14,"roomOwner":"nico","roomClientCount":3,"preClientNickname":"nico1","nextClientNickname":"nico2","nextClientId":2}
CODE
- CODE_GAME_OVERTYPE
- JSONDATA
- 如下
字段名 | 含义 |
---|---|
winnerNickname | 获胜者昵称 |
winnerType | 获胜者类型(地主?农民) |
参考数据:
{"winnerNickname":"nico","winnerType":"LANDLORD?PEASANT"}