2022-03-02 20:56:37 +08:00
|
|
|
|
# FreeKill 的通信
|
|
|
|
|
|
|
|
|
|
> [dev](./index.md) > 通信
|
|
|
|
|
|
|
|
|
|
___
|
|
|
|
|
|
|
|
|
|
## 概述
|
|
|
|
|
|
|
|
|
|
FreeKill使用UTF-8文本进行通信。基本的通信格式为JSON数组:
|
|
|
|
|
|
|
|
|
|
`[requestId, packetType, command, jsonData]`
|
|
|
|
|
|
|
|
|
|
其中:
|
|
|
|
|
|
|
|
|
|
- requestId用来在request型通信使用,用来确保收到的回复和发出的请求相对应。
|
|
|
|
|
- packetType用来确定这条消息的类型以及发送的目的地。
|
|
|
|
|
- command用来表示消息的类型。使用首字母大写的驼峰式命名,因为下划线命名会造成额外的网络开销。
|
|
|
|
|
- jsonData保存着这个消息的额外信息,必须是一个JSON数组。数组中的具体内容详见源码及注释。
|
|
|
|
|
|
|
|
|
|
FreeKill通信有三大类型:请求(Request)、回复(Reply)和通知(Notification)。
|
|
|
|
|
|
|
|
|
|
___
|
|
|
|
|
|
|
|
|
|
## 从连接上到进入大厅
|
|
|
|
|
|
|
|
|
|
想要启动服务器,需要通过命令行终端:
|
|
|
|
|
|
|
|
|
|
```sh
|
|
|
|
|
$ ./FreeKill -s <port>
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
`<port>`是服务器运行的端口号,如果不带任何参数则启动GUI界面,在GUI界面里面只能加入服务器或者单机游戏。
|
|
|
|
|
|
|
|
|
|
服务器以TCP方式监听。在默认情况下(比如单机启动),服务器的端口号是9527。
|
|
|
|
|
|
2022-03-24 21:23:42 +08:00
|
|
|
|
每当任何一个客户端连接上了之后,游戏会先进行以下流程:
|
|
|
|
|
|
|
|
|
|
1. 检查IP是否被封禁。 // TODO: 数据库
|
|
|
|
|
2. 检查客户端的延迟是否小于30秒。
|
|
|
|
|
3. 在网络检测环节,若客户端网速达标的话,客户端应该会发回一个字符串。这个字符串保存着用户的用户名和密码,服务端检查这个字符串是否合法。
|
2022-03-27 14:49:41 +08:00
|
|
|
|
4. 上述检查都通过后,重连(TODO:)
|
2022-03-24 21:23:42 +08:00
|
|
|
|
5. 不要重连的话,服务端便为新连接新建一个`ServerPlayer`对象,并将其添加到大厅中。
|
|
|
|
|
|
|
|
|
|
___
|
|
|
|
|
|
|
|
|
|
## 大厅和房间
|
|
|
|
|
|
|
|
|
|
大厅(Lobby)是一个比较特殊的房间。除了大厅之外,所有的房间都被作为游戏房间对待。
|
|
|
|
|
|
|
|
|
|
对于普通房间而言,有这几个特点:
|
|
|
|
|
|
|
|
|
|
1. 只要房间被添加玩家,那么那名玩家就自动从大厅移除。
|
|
|
|
|
2. 当玩家离开房间时,玩家便会自动进入大厅。
|
|
|
|
|
3. 当所有玩家都离开房间后,房间被销毁。
|
|
|
|
|
|
|
|
|
|
大厅的特点:
|
|
|
|
|
|
|
|
|
|
1. 只要有玩家进入,就刷新一次房间列表。
|
|
|
|
|
|
|
|
|
|
> 因为上述特点都是通过信号槽实现的,通过阅读代码不易发现,故记录之。
|
|
|
|
|
|
|
|
|
|
___
|
|
|
|
|
|
|
|
|
|
## 对掉线的处理
|
|
|
|
|
|
|
|
|
|
因为每个连接都对应着一个`new ClientSocket`和`new ServerPlayer`,所以对于掉线的处理要慎重,处理不当会导致内存泄漏以及各种奇怪的错误。
|
|
|
|
|
|
|
|
|
|
一般来说掉线有以下几种情况:
|
|
|
|
|
|
|
|
|
|
1. 刚刚登入,服务端还在检测时掉线。
|
|
|
|
|
2. 在大厅里面掉线。
|
|
|
|
|
3. 在未开始游戏的房间里面掉线。
|
|
|
|
|
4. 在已开始游戏的房间里掉线。
|
|
|
|
|
|
|
|
|
|
首先对所有的这些情况,都应该把ClientSocket释放掉。这部分代码写在[server_socket.cpp](../../src/network/server_socket.cpp)里面。
|
|
|
|
|
|
|
|
|
|
对于2、3两种情况,都算是在游戏开始之前的房间中掉线。这种情况下直接从房间中删除这个玩家,并告诉其他玩家一声,然后从服务器玩家列表中也删除那名玩家。但对于情况3,因为从普通房间删除玩家的话,那名玩家会自动进入大厅,所以需要大厅再删除一次玩家。
|
|
|
|
|
|
|
|
|
|
对于情况4,因为游戏已经开始,所以不能直接删除玩家,需要把玩家的状态设为“离线”并继续游戏。在游戏结束后,若玩家仍未重连,则按情况2、3处理。
|
|
|
|
|
|
2022-03-27 14:49:41 +08:00
|
|
|
|
> Note: 这部分处理见于ServerPlayer类的析构函数。
|
|
|
|
|
|
2022-03-24 21:23:42 +08:00
|
|
|
|
___
|
|
|
|
|
|
|
|
|
|
## 断线重连(TODO)
|
|
|
|
|
|
|
|
|
|
根据用户名找到掉线的那位玩家,将玩家的状态设置为“在线”,并将房间的状态都发送给他即可。
|
|
|
|
|
|
|
|
|
|
但是为了[UI不出错](./ui.md#mainStack),依然需要对重连的玩家走一遍进大厅的流程。
|
|
|
|
|
|
|
|
|
|
___
|
|
|
|
|
|
|
|
|
|
## 旁观(TODO)
|
|
|
|
|
|
|
|
|
|
因为房间不允许加入比玩家上限的玩家,可以考虑在房间里新建一个列表存储旁观中的玩家。但是这样或许会让某些处理(如掉线)变得复杂化。
|
|
|
|
|
|
|
|
|
|
也可以考虑旁观者在服务端中处于大厅中,自己的端中在旁观房间。但是这样的话无法在房间中发送聊天。
|
|
|
|
|
|
|
|
|
|
所以还是让旁观者在房间中吧。可以给ServerPlayer设置个属性保存正在旁观的房间的id。
|
|
|
|
|
|
|
|
|
|
旁观者的处理方式或许可以像观看录像那样,过滤所有的request事件。这样就确确实实只能看着了。
|
|
|
|
|
|
|
|
|
|
而不过滤request的旁观就可以理解为操控其他玩家了。hhh
|