changed code style, doc

This commit is contained in:
Notify-ctrl 2022-03-02 20:56:37 +08:00
parent 9ed3f1bf3f
commit 8fb08a8ece
23 changed files with 158 additions and 89 deletions

1
.gitignore vendored
View File

@ -1,5 +1,6 @@
build/ build/
.kdev4/ .kdev4/
.vscode/
*.user *.user
*-swp *-swp
*.kdev4 *.kdev4

7
README.md Normal file
View File

@ -0,0 +1,7 @@
# FreeKill
___
试图打造一个最适合diy玩家游玩的民间三国杀所有的一切都是为了更好的制作diy而设计的。
项目仍处于啥都没有的阶段。不过我为了整理思路,也写了点[文档](./doc/index.md)。

9
doc/dev/index.md Normal file
View File

@ -0,0 +1,9 @@
# FreeKill 开发文档
> dev
___
FreeKill采用Qt框架提供底层支持在上层使用lua语言开发。在UI方面使用的是Qt Quick。
- [通信](./protocol.md)

36
doc/dev/protocol.md Normal file
View File

@ -0,0 +1,36 @@
# 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。
每当任何一个客户端连接上了之后,客户端进入大厅。

5
doc/diy/index.md Normal file
View File

@ -0,0 +1,5 @@
# 如何用FreeKill实现diy武将
> diy
___

6
doc/index.md Normal file
View File

@ -0,0 +1,6 @@
# FreeKill 文档
___
- [开发者文档](./dev/index.md)
- [DIY玩家文档](./diy/index.md)

View File

@ -4,15 +4,15 @@ freekill.client_callback = {}
function Client:initialize() function Client:initialize()
self.client = freekill.ClientInstance self.client = freekill.ClientInstance
self.notifyUI = function(self, command, json_data) self.notifyUI = function(self, command, jsonData)
freekill.Backend:emitNotifyUI(command, json_data) freekill.Backend:emitNotifyUI(command, jsonData)
end end
self.client.callback = function(_self, command, json_data) self.client.callback = function(_self, command, jsonData)
local cb = freekill.client_callback[command] local cb = freekill.client_callback[command]
if (type(cb) == "function") then if (type(cb) == "function") then
cb(json_data) cb(jsonData)
else else
self:notifyUI(command, json_data); self:notifyUI(command, jsonData);
end end
end end
end end

View File

@ -4,36 +4,36 @@ freekill.server_callback = {}
function Server:initialize() function Server:initialize()
self.server = freekill.ServerInstance self.server = freekill.ServerInstance
self.server.callback = function(_self, command, json_data) self.server.callback = function(_self, command, jsonData)
local cb = freekill.server_callback[command] local cb = freekill.server_callback[command]
if (type(cb) == "function") then if (type(cb) == "function") then
cb(json_data) cb(jsonData)
else else
print("Server error: Unknown command " .. command); print("Server error: Unknown command " .. command);
end end
end end
end end
freekill.server_callback["create_room"] = function(json_data) freekill.server_callback["CreateRoom"] = function(jsonData)
-- json_data: [ int uid, string name, int capacity ] -- jsonData: [ int uid, string name, int capacity ]
local data = json.decode(json_data) local data = json.decode(jsonData)
local owner = freekill.ServerInstance:findPlayer(tonumber(data[1])) local owner = freekill.ServerInstance:findPlayer(tonumber(data[1]))
local roomName = data[2] local roomName = data[2]
local capacity = data[3] local capacity = data[3]
freekill.ServerInstance:createRoom(owner, roomName, capacity) freekill.ServerInstance:createRoom(owner, roomName, capacity)
end end
freekill.server_callback["enter_room"] = function(json_data) freekill.server_callback["EnterRoom"] = function(jsonData)
-- json_data: [ int uid, int roomId ] -- jsonData: [ int uid, int roomId ]
local data = json.decode(json_data) local data = json.decode(jsonData)
local player = freekill.ServerInstance:findPlayer(tonumber(data[1])) local player = freekill.ServerInstance:findPlayer(tonumber(data[1]))
local room = freekill.ServerInstance:findRoom(tonumber(data[2])) local room = freekill.ServerInstance:findRoom(tonumber(data[2]))
room:addPlayer(player) room:addPlayer(player)
end end
freekill.server_callback["quit_room"] = function(json_data) freekill.server_callback["QuitRoom"] = function(jsonData)
-- json_data: [ int uid ] -- jsonData: [ int uid ]
local data = json.decode(json_data) local data = json.decode(jsonData)
local player = freekill.ServerInstance:findPlayer(tonumber(data[1])) local player = freekill.ServerInstance:findPlayer(tonumber(data[1]))
local room = player:getRoom() local room = player:getRoom()
if not room:isLobby() then if not room:isLobby() then

View File

@ -46,7 +46,7 @@ Item {
mainWindow.busy = true; mainWindow.busy = true;
mainStack.pop(); mainStack.pop();
Backend.notifyServer( Backend.notifyServer(
"create_room", "CreateRoom",
JSON.stringify([roomName.text, playerNum.value]) JSON.stringify([roomName.text, playerNum.value])
); );
} }

View File

@ -11,7 +11,7 @@ Item {
text: "quit" text: "quit"
onClicked: { onClicked: {
mainStack.pop(); mainStack.pop();
Backend.notifyServer("quit_room", "[]"); Backend.notifyServer("QuitRoom", "[]");
} }
} }
} }

View File

@ -9,25 +9,31 @@ Window {
width: 720 width: 720
height: 480 height: 480
property var callbacks: ({ property var callbacks: ({
"error_msg": function(json_data) { "ErrorMsg": function(jsonData) {
toast.show(json_data); toast.show(jsonData);
mainWindow.busy = false; mainWindow.busy = false;
}, },
"enter_lobby": function(json_data) { "EnterLobby": function(jsonData) {
if (mainStack.depth === 1) { if (mainStack.depth === 1) {
mainStack.push(lobby); mainStack.push(lobby);
} }
mainWindow.busy = false; mainWindow.busy = false;
}, },
"enter_room": function(json_data) { "EnterRoom": function(jsonData) {
mainStack.push(room); mainStack.push(room);
mainWindow.busy = false; mainWindow.busy = false;
}, },
"update_room_list": function(json_data) { "UpdateRoomList": function(jsonData) {
let current = mainStack.currentItem; // should be lobby let current = mainStack.currentItem; // should be lobby
current.roomModel.clear(); current.roomModel.clear();
JSON.parse(json_data).forEach(function(room) { JSON.parse(jsonData).forEach(function(room) {
current.roomModel.append(room); current.roomModel.append({
roomId: room[0],
roomName: room[1],
gameMode: room[2],
playerNum: room[3],
capacity: room[4],
});
}); });
} }
}) })
@ -110,12 +116,12 @@ Window {
Connections { Connections {
target: Backend target: Backend
function onNotifyUI(command, json_data) { function onNotifyUI(command, jsonData) {
let cb = callbacks[command] let cb = callbacks[command]
if (typeof(cb) === "function") { if (typeof(cb) === "function") {
cb(json_data); cb(jsonData);
} else { } else {
callbacks["error_msg"]("Unknown command " + command + "!"); callbacks["ErrorMsg"]("Unknown command " + command + "!");
} }
} }
} }

View File

@ -32,20 +32,20 @@ void Client::connectToHost(const QHostAddress& server, ushort port)
router->getSocket()->connectToHost(server, port); router->getSocket()->connectToHost(server, port);
} }
void Client::requestServer(const QString& command, const QString& json_data, int timeout) void Client::requestServer(const QString& command, const QString& jsonData, int timeout)
{ {
int type = Router::TYPE_REQUEST | Router::SRC_CLIENT | Router::DEST_SERVER; int type = Router::TYPE_REQUEST | Router::SRC_CLIENT | Router::DEST_SERVER;
router->request(type, command, json_data, timeout); router->request(type, command, jsonData, timeout);
} }
void Client::replyToServer(const QString& command, const QString& json_data) void Client::replyToServer(const QString& command, const QString& jsonData)
{ {
int type = Router::TYPE_REPLY | Router::SRC_CLIENT | Router::DEST_SERVER; int type = Router::TYPE_REPLY | Router::SRC_CLIENT | Router::DEST_SERVER;
router->reply(type, command, json_data); router->reply(type, command, jsonData);
} }
void Client::notifyServer(const QString& command, const QString& json_data) void Client::notifyServer(const QString& command, const QString& jsonData)
{ {
int type = Router::TYPE_NOTIFICATION | Router::SRC_CLIENT | Router::DEST_SERVER; int type = Router::TYPE_NOTIFICATION | Router::SRC_CLIENT | Router::DEST_SERVER;
router->notify(type, command, json_data); router->notify(type, command, jsonData);
} }

View File

@ -20,11 +20,11 @@ public:
// void login // void login
void requestServer(const QString &command, void requestServer(const QString &command,
const QString &json_data, int timeout = -1); const QString &jsonData, int timeout = -1);
void replyToServer(const QString &command, const QString &json_data); void replyToServer(const QString &command, const QString &jsonData);
void notifyServer(const QString &command, const QString &json_data); void notifyServer(const QString &command, const QString &jsonData);
void callLua(const QString &command, const QString &json_data); void callLua(const QString &command, const QString &jsonData);
LuaFunction callback; LuaFunction callback;
signals: signals:

View File

@ -50,7 +50,7 @@ void Router::setReplyReadySemaphore(QSemaphore *semaphore)
} }
void Router::request(int type, const QString& command, void Router::request(int type, const QString& command,
const QString& json_data, int timeout) const QString& jsonData, int timeout)
{ {
// In case a request is called without a following waitForReply call // In case a request is called without a following waitForReply call
if (replyReadySemaphore.available() > 0) if (replyReadySemaphore.available() > 0)
@ -70,30 +70,30 @@ void Router::request(int type, const QString& command,
body << requestId; body << requestId;
body << type; body << type;
body << command; body << command;
body << json_data; body << jsonData;
body << timeout; body << timeout;
emit messageReady(QJsonDocument(body).toJson(QJsonDocument::Compact)); emit messageReady(QJsonDocument(body).toJson(QJsonDocument::Compact));
} }
void Router::reply(int type, const QString& command, const QString& json_data) void Router::reply(int type, const QString& command, const QString& jsonData)
{ {
QJsonArray body; QJsonArray body;
body << this->requestId; body << this->requestId;
body << type; body << type;
body << command; body << command;
body << json_data; body << jsonData;
emit messageReady(QJsonDocument(body).toJson(QJsonDocument::Compact)); emit messageReady(QJsonDocument(body).toJson(QJsonDocument::Compact));
} }
void Router::notify(int type, const QString& command, const QString& json_data) void Router::notify(int type, const QString& command, const QString& jsonData)
{ {
QJsonArray body; QJsonArray body;
body << -2; // requestId = -2 mean this is for notification body << -2; // requestId = -2 mean this is for notification
body << type; body << type;
body << command; body << command;
body << json_data; body << jsonData;
emit messageReady(QJsonDocument(body).toJson(QJsonDocument::Compact)); emit messageReady(QJsonDocument(body).toJson(QJsonDocument::Compact));
} }
@ -150,14 +150,14 @@ void Router::handlePacket(const QByteArray& rawPacket)
int requestId = packet[0].toInt(); int requestId = packet[0].toInt();
int type = packet[1].toInt(); int type = packet[1].toInt();
QString command = packet[2].toString(); QString command = packet[2].toString();
QString json_data = packet[3].toString(); QString jsonData = packet[3].toString();
if (type & TYPE_NOTIFICATION) { if (type & TYPE_NOTIFICATION) {
if (type & DEST_CLIENT) { if (type & DEST_CLIENT) {
ClientInstance->callLua(command, json_data); ClientInstance->callLua(command, jsonData);
} else { } else {
// Add the uid of sender to json_data // Add the uid of sender to jsonData
QJsonArray arr = QJsonDocument::fromJson(json_data.toUtf8()).array(); QJsonArray arr = QJsonDocument::fromJson(jsonData.toUtf8()).array();
arr.prepend( arr.prepend(
(int)qobject_cast<ServerPlayer *>(parent())->getUid() (int)qobject_cast<ServerPlayer *>(parent())->getUid()
); );
@ -169,7 +169,7 @@ void Router::handlePacket(const QByteArray& rawPacket)
this->requestTimeout = packet[4].toInt(); this->requestTimeout = packet[4].toInt();
if (type & DEST_CLIENT) { if (type & DEST_CLIENT) {
qobject_cast<Client *>(parent())->callLua(command, json_data); qobject_cast<Client *>(parent())->callLua(command, jsonData);
} else { } else {
// requesting server is not allowed // requesting server is not allowed
Q_ASSERT(false); Q_ASSERT(false);
@ -187,7 +187,7 @@ void Router::handlePacket(const QByteArray& rawPacket)
requestStartTime.secsTo(QDateTime::currentDateTime())) requestStartTime.secsTo(QDateTime::currentDateTime()))
return; return;
m_reply = json_data; m_reply = jsonData;
// TODO: callback? // TODO: callback?
qDebug() << rawPacket << Qt::endl; qDebug() << rawPacket << Qt::endl;

View File

@ -37,9 +37,9 @@ public:
void setReplyReadySemaphore(QSemaphore *semaphore); void setReplyReadySemaphore(QSemaphore *semaphore);
void request(int type, const QString &command, void request(int type, const QString &command,
const QString &json_data, int timeout); const QString &jsonData, int timeout);
void reply(int type, const QString &command, const QString &json_data); void reply(int type, const QString &command, const QString &jsonData);
void notify(int type, const QString &command, const QString &json_data); void notify(int type, const QString &command, const QString &jsonData);
int getTimeout() const; int getTimeout() const;

View File

@ -80,9 +80,9 @@ void Room::addPlayer(ServerPlayer *player)
players.append(player); players.append(player);
player->setRoom(this); player->setRoom(this);
if (isLobby()) { if (isLobby()) {
player->doNotify("enter_lobby", "{}"); player->doNotify("EnterLobby", "[]");
} else { } else {
player->doNotify("enter_room", "{}"); player->doNotify("EnterRoom", "[]");
} }
qDebug() << "Player #" << player->getUid() << " entered room"; qDebug() << "Player #" << player->getUid() << " entered room";
emit playerAdded(player); emit playerAdded(player);
@ -99,7 +99,7 @@ void Room::removePlayer(ServerPlayer *player)
emit abandoned(); emit abandoned();
} else if (player == owner) { } else if (player == owner) {
setOwner(players.first()); setOwner(players.first());
owner->doNotify("room_owner", "{}"); owner->doNotify("RoomOwner", "[]");
} }
} }
@ -143,10 +143,10 @@ void Room::doNotify(const QList<ServerPlayer *> targets, int timeout)
} }
void Room::doBroadcastNotify(const QList<ServerPlayer *> targets, void Room::doBroadcastNotify(const QList<ServerPlayer *> targets,
const QString& command, const QString& json_data) const QString& command, const QString& jsonData)
{ {
foreach (ServerPlayer *p, targets) { foreach (ServerPlayer *p, targets) {
p->doNotify(command, json_data); p->doNotify(command, jsonData);
} }
} }

View File

@ -44,7 +44,7 @@ public:
void doBroadcastNotify( void doBroadcastNotify(
const QList<ServerPlayer *> targets, const QList<ServerPlayer *> targets,
const QString &command, const QString &command,
const QString &json_data const QString &jsonData
); );
signals: signals:

View File

@ -74,17 +74,17 @@ void Server::updateRoomList()
{ {
QJsonArray arr; QJsonArray arr;
foreach (Room *room, rooms) { foreach (Room *room, rooms) {
QJsonObject obj; QJsonArray obj;
obj["roomId"] = (int)room->getId(); obj << (int)room->getId(); // roomId
obj["roomName"] = room->getName(); obj << room->getName(); // roomName
obj["gameMode"] = "Role"; obj << "Role"; // gameMode
obj["playerNum"] = room->getPlayers().count(); obj << room->getPlayers().count(); // playerNum
obj["capacity"] = (int)room->getCapacity(); obj << (int)room->getCapacity(); // capacity
arr << obj; arr << obj;
} }
lobby()->doBroadcastNotify( lobby()->doBroadcastNotify(
lobby()->getPlayers(), lobby()->getPlayers(),
"update_room_list", "UpdateRoomList",
QJsonDocument(arr).toJson() QJsonDocument(arr).toJson()
); );
} }
@ -100,7 +100,6 @@ void Server::processNewConnection(ClientSocket* client)
qDebug() << "His address is " << client->peerAddress(); qDebug() << "His address is " << client->peerAddress();
#endif #endif
//player->doNotify("enter_lobby", "{}");
lobby()->addPlayer(player); lobby()->addPlayer(player);
} }
@ -114,7 +113,7 @@ void Server::onRoomAbandoned()
void Server::onUserDisconnected() void Server::onUserDisconnected()
{ {
// TODO qobject_cast<ServerPlayer *>(sender())->setStateString("offline");
} }
void Server::onUserStateChanged() void Server::onUserStateChanged()

View File

@ -31,7 +31,7 @@ public:
void updateRoomList(); void updateRoomList();
void callLua(const QString &command, const QString &json_data); void callLua(const QString &command, const QString &jsonData);
LuaFunction callback; LuaFunction callback;
signals: signals:

View File

@ -52,22 +52,22 @@ void ServerPlayer::speak(const QString& message)
; ;
} }
void ServerPlayer::doRequest(const QString& command, const QString& json_data, int timeout) void ServerPlayer::doRequest(const QString& command, const QString& jsonData, int timeout)
{ {
int type = Router::TYPE_REQUEST | Router::SRC_SERVER | Router::DEST_CLIENT; int type = Router::TYPE_REQUEST | Router::SRC_SERVER | Router::DEST_CLIENT;
router->request(type, command, json_data, timeout); router->request(type, command, jsonData, timeout);
} }
void ServerPlayer::doReply(const QString& command, const QString& json_data) void ServerPlayer::doReply(const QString& command, const QString& jsonData)
{ {
int type = Router::TYPE_REPLY | Router::SRC_SERVER | Router::DEST_CLIENT; int type = Router::TYPE_REPLY | Router::SRC_SERVER | Router::DEST_CLIENT;
router->reply(type, command, json_data); router->reply(type, command, jsonData);
} }
void ServerPlayer::doNotify(const QString& command, const QString& json_data) void ServerPlayer::doNotify(const QString& command, const QString& jsonData)
{ {
int type = Router::TYPE_NOTIFICATION | Router::SRC_SERVER | Router::DEST_CLIENT; int type = Router::TYPE_NOTIFICATION | Router::SRC_SERVER | Router::DEST_CLIENT;
router->notify(type, command, json_data); router->notify(type, command, jsonData);
} }
void ServerPlayer::prepareForRequest(const QString& command, const QVariant& data) void ServerPlayer::prepareForRequest(const QString& command, const QVariant& data)

View File

@ -25,9 +25,9 @@ public:
void speak(const QString &message); void speak(const QString &message);
void doRequest(const QString &command, void doRequest(const QString &command,
const QString &json_data, int timeout = -1); const QString &jsonData, int timeout = -1);
void doReply(const QString &command, const QString &json_data); void doReply(const QString &command, const QString &jsonData);
void doNotify(const QString &command, const QString &json_data); void doNotify(const QString &command, const QString &jsonData);
void prepareForRequest(const QString &command, void prepareForRequest(const QString &command,
const QVariant &data = QVariant()); const QVariant &data = QVariant());

View File

@ -18,7 +18,7 @@ void QmlBackend::startServer(ushort port)
if (!server->listen(QHostAddress::Any, port)) { if (!server->listen(QHostAddress::Any, port)) {
server->deleteLater(); server->deleteLater();
emit notifyUI("error_msg", tr("Cannot start server!")); emit notifyUI("ErrorMsg", tr("Cannot start server!"));
} }
} }
} }
@ -28,7 +28,7 @@ void QmlBackend::joinServer(QString address)
class Client *client = new class Client(this); class Client *client = new class Client(this);
connect(client, &Client::error_message, [this, client](const QString &msg){ connect(client, &Client::error_message, [this, client](const QString &msg){
client->deleteLater(); client->deleteLater();
emit notifyUI("error_msg", msg); emit notifyUI("ErrorMsg", msg);
}); });
QString addr = "127.0.0.1"; QString addr = "127.0.0.1";
ushort port = 9527u; ushort port = 9527u;
@ -44,14 +44,14 @@ void QmlBackend::joinServer(QString address)
client->connectToHost(QHostAddress(addr), port); client->connectToHost(QHostAddress(addr), port);
} }
void QmlBackend::replyToServer(const QString& command, const QString& json_data) void QmlBackend::replyToServer(const QString& command, const QString& jsonData)
{ {
ClientInstance->replyToServer(command, json_data); ClientInstance->replyToServer(command, jsonData);
} }
void QmlBackend::notifyServer(const QString& command, const QString& json_data) void QmlBackend::notifyServer(const QString& command, const QString& jsonData)
{ {
ClientInstance->notifyServer(command, json_data); ClientInstance->notifyServer(command, jsonData);
} }
void QmlBackend::quitLobby() void QmlBackend::quitLobby()

View File

@ -18,18 +18,18 @@ public:
QmlBackend(QObject *parent = nullptr); QmlBackend(QObject *parent = nullptr);
// For lua use // For lua use
void emitNotifyUI(const char *command, const char *json_data) { void emitNotifyUI(const char *command, const char *jsonData) {
emit notifyUI(command, json_data); emit notifyUI(command, jsonData);
} }
signals: signals:
void notifyUI(const QString &command, const QString &json_data); void notifyUI(const QString &command, const QString &jsonData);
public slots: public slots:
void startServer(ushort port); void startServer(ushort port);
void joinServer(QString address); void joinServer(QString address);
void replyToServer(const QString &command, const QString &json_data); void replyToServer(const QString &command, const QString &jsonData);
void notifyServer(const QString &command, const QString &json_data); void notifyServer(const QString &command, const QString &jsonData);
// Lobby // Lobby
void quitLobby(); void quitLobby();