diff --git a/lua/client/client.lua b/lua/client/client.lua index 0ed8b6f8..5fb8f608 100644 --- a/lua/client/client.lua +++ b/lua/client/client.lua @@ -21,5 +21,9 @@ freekill.client_callback["enter_lobby"] = function(json_data) ClientInstance:notifyUI("enter_lobby", json_data) end +freekill.client_callback["enter_room"] = function(json_data) + ClientInstance:notifyUI("enter_room", json_data) +end + -- Create ClientInstance (used by Lua) ClientInstance = Client:new() diff --git a/lua/server/server.lua b/lua/server/server.lua index 67b33266..5ea55f11 100644 --- a/lua/server/server.lua +++ b/lua/server/server.lua @@ -15,12 +15,30 @@ function Server:initialize() end freekill.server_callback["create_room"] = function(json_data) - -- json_data: [ int id, string name, int capacity ] + -- json_data: [ int uid, string name, int capacity ] local data = json.decode(json_data) - local owner = freekill.ServerInstance:findPlayer(data[1]) + local owner = freekill.ServerInstance:findPlayer(tonumber(data[1])) local roomName = data[2] local capacity = data[3] freekill.ServerInstance:createRoom(owner, roomName, capacity) end +freekill.server_callback["enter_room"] = function(json_data) + -- json_data: [ int uid, int roomId ] + local data = json.decode(json_data) + local player = freekill.ServerInstance:findPlayer(tonumber(data[1])) + local room = freekill.ServerInstance:findRoom(tonumber(data[2])) + room:addPlayer(player) +end + +freekill.server_callback["quit_room"] = function(json_data) + -- json_data: [ int uid ] + local data = json.decode(json_data) + local player = freekill.ServerInstance:findPlayer(tonumber(data[1])) + local room = player:getRoom() + if not room:isLobby() then + room:removePlayer(player) + end +end + ServerInstance = Server:new() diff --git a/qml/Page/Room.qml b/qml/Page/Room.qml deleted file mode 100644 index 22c5da15..00000000 --- a/qml/Page/Room.qml +++ /dev/null @@ -1,8 +0,0 @@ -import QtQuick 2.15 -import QtQuick.Controls 2.0 -import QtQuick.Window 2.0 - -Item { - id: root -} - diff --git a/qml/Pages/CreateRoom.qml b/qml/Pages/CreateRoom.qml new file mode 100644 index 00000000..fe7b0397 --- /dev/null +++ b/qml/Pages/CreateRoom.qml @@ -0,0 +1,63 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.15 + +Item { + id: root + Frame { + anchors.centerIn: parent + Column { + x: 32 + y: 20 + spacing: 20 + + RowLayout { + anchors.rightMargin: 8 + spacing: 16 + Text { + text: "Room Name" + } + TextField { + id: roomName + font.pixelSize: 18 + text: "tmp's Room" + } + } + + RowLayout { + anchors.rightMargin: 8 + spacing: 16 + Text { + text: "Player num" + } + SpinBox { + id: playerNum + from: 2 + to: 8 + } + } + + RowLayout { + anchors.rightMargin: 8 + spacing: 16 + Button { + text: "OK" + onClicked: { + mainWindow.busy = true; + mainStack.pop(); + Backend.notifyServer( + "create_room", + JSON.stringify([roomName.text, playerNum.value]) + ); + } + } + Button { + text: "Cancel" + onClicked: { + mainStack.pop(); + } + } + } + } + } +} diff --git a/qml/Page/Init.qml b/qml/Pages/Init.qml similarity index 74% rename from qml/Page/Init.qml rename to qml/Pages/Init.qml index c49f6525..35c8ce58 100644 --- a/qml/Page/Init.qml +++ b/qml/Pages/Init.qml @@ -1,6 +1,5 @@ import QtQuick 2.15 import QtQuick.Controls 2.0 -import QtQuick.Window 2.0 Item { id: root @@ -20,16 +19,16 @@ Item { Button { text: "Join Server" onClicked: { - mainWindow.state = "busy"; - mainWindow.busyString = "Connecting to host..."; + mainWindow.busy = true; + toast.show("Connecting to host..."); Backend.joinServer(server_addr.text); } } Button { text: "Console start" onClicked: { - mainWindow.state = "busy"; - mainWindow.busyString = "Connecting to host..."; + mainWindow.busy = true; + toast.show("Connecting to host..."); Backend.startServer(9527); Backend.joinServer("127.0.0.1"); } diff --git a/qml/Page/Lobby.qml b/qml/Pages/Lobby.qml similarity index 66% rename from qml/Page/Lobby.qml rename to qml/Pages/Lobby.qml index 885b7e90..b548bc4a 100644 --- a/qml/Page/Lobby.qml +++ b/qml/Pages/Lobby.qml @@ -40,7 +40,13 @@ Item { hoverEnabled: true onEntered: { parent.color = "blue" } onExited: { parent.color = "black" } - onClicked: {} + onClicked: { + mainWindow.busy = true; + Backend.notifyServer( + "enter_room", + JSON.stringify([roomId]) + ); + } } } } @@ -85,7 +91,9 @@ Item { } Button { text: "Create Room" - onClicked: {} + onClicked: { + mainStack.push(createRoom); + } } Button { text: "Generals Overview" @@ -101,12 +109,42 @@ Item { } Button { text: "Exit Lobby" + onClicked: { + toast.show("Goodbye."); + Backend.quitLobby(); + mainStack.pop(); + } } } } + Loader { + id: lobby_dialog + z: 1000 + onSourceChanged: { + if (item === null) + return; + item.finished.connect(function(){ + source = ""; + }); + item.widthChanged.connect(function(){ + lobby_dialog.moveToCenter(); + }); + item.heightChanged.connect(function(){ + lobby_dialog.moveToCenter(); + }); + moveToCenter(); + } + + function moveToCenter() + { + item.x = Math.round((root.width - item.width) / 2); + item.y = Math.round(root.height * 0.67 - item.height / 2); + } + } + Component.onCompleted: { - // toast.show("Welcome to FreeKill lobby!") + toast.show("Welcome to FreeKill lobby!"); } } diff --git a/qml/Pages/Room.qml b/qml/Pages/Room.qml new file mode 100644 index 00000000..0c969600 --- /dev/null +++ b/qml/Pages/Room.qml @@ -0,0 +1,18 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.0 + +Item { + id: root + Text { + anchors.centerIn: parent + text: "You are in room." + } + Button { + text: "quit" + onClicked: { + mainStack.pop(); + Backend.notifyServer("quit_room", "[]"); + } + } +} + diff --git a/qml/main.qml b/qml/main.qml index 76ed0efa..e387798e 100644 --- a/qml/main.qml +++ b/qml/main.qml @@ -1,6 +1,7 @@ import QtQuick 2.15 import QtQuick.Controls 2.0 import QtQuick.Window 2.0 +import "Pages" Window { id: mainWindow @@ -10,46 +11,52 @@ Window { property var callbacks: ({ "error_msg": function(json_data) { toast.show(json_data); - if (mainWindow.state === "busy") - mainWindow.state = "init"; + mainWindow.busy = false; }, "enter_lobby": function(json_data) { - mainWindow.state = "lobby"; + if (mainStack.depth === 1) { + mainStack.push(lobby); + } + mainWindow.busy = false; + }, + "enter_room": function(json_data) { + mainStack.push(room); + mainWindow.busy = false; } }) - Loader { - id: mainLoader - source: "Page/Init.qml" + StackView { + id: mainStack + visible: !mainWindow.busy + initialItem: init anchors.fill: parent } - property string state: "init" - - onStateChanged: { - switch (state) { - case "init": - mainLoader.source = "Page/Init.qml"; - break; - case "lobby": - mainLoader.source = "Page/Lobby.qml"; - break; - case "room": - mainLoader.source = "Page/Room.qml"; - break; - case "busy": - mainLoader.source = ""; - break; - default: break; - } + Component { + id: init + Init {} } - property string busyString: "Busy" + Component { + id: lobby + Lobby {} + } + Component { + id: room + Room {} + } + + Component { + id: createRoom + CreateRoom {} + } + + property bool busy: false BusyIndicator { running: true anchors.centerIn: parent - visible: mainWindow.state === "busy" + visible: mainWindow.busy === true } Rectangle { @@ -83,14 +90,14 @@ Window { ScriptAction { script: { - toast.opacity = 0 + toast.opacity = 0; } } } function show(text) { - opacity = 1 - toast_text.text = text + opacity = 1; + toast_text.text = text; } } diff --git a/src/client/client.cpp b/src/client/client.cpp index 5d16316e..dd27cf68 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -23,6 +23,7 @@ Client::Client(QObject* parent) Client::~Client() { ClientInstance = nullptr; + router->getSocket()->disconnectFromHost(); router->getSocket()->deleteLater(); } @@ -39,12 +40,12 @@ void Client::requestServer(const QString& command, const QString& json_data, int void Client::replyToServer(const QString& command, const QString& json_data) { - int type = Router::TYPE_REQUEST | Router::SRC_CLIENT | Router::DEST_SERVER; + int type = Router::TYPE_REPLY | Router::SRC_CLIENT | Router::DEST_SERVER; router->reply(type, command, json_data); } void Client::notifyServer(const QString& command, const QString& json_data) { - int type = Router::TYPE_REQUEST | Router::SRC_CLIENT | Router::DEST_SERVER; + int type = Router::TYPE_NOTIFICATION | Router::SRC_CLIENT | Router::DEST_SERVER; router->notify(type, command, json_data); } diff --git a/src/network/router.cpp b/src/network/router.cpp index 51a597bc..bd446c95 100644 --- a/src/network/router.cpp +++ b/src/network/router.cpp @@ -3,6 +3,7 @@ #include "router.h" #include "client.h" #include "server.h" +#include "serverplayer.h" Router::Router(QObject *parent, ClientSocket *socket, RouterType type) : QObject(parent) @@ -153,9 +154,14 @@ void Router::handlePacket(const QByteArray& rawPacket) if (type & TYPE_NOTIFICATION) { if (type & DEST_CLIENT) { - qobject_cast(parent())->callLua(command, json_data); + ClientInstance->callLua(command, json_data); } else { - qDebug() << rawPacket << Qt::endl; + // Add the uid of sender to json_data + QJsonArray arr = QJsonDocument::fromJson(json_data.toUtf8()).array(); + arr.prepend( + (int)qobject_cast(parent())->getUid() + ); + ServerInstance->callLua(command, QJsonDocument(arr).toJson()); } } else if (type & TYPE_REQUEST) { @@ -165,7 +171,8 @@ void Router::handlePacket(const QByteArray& rawPacket) if (type & DEST_CLIENT) { qobject_cast(parent())->callLua(command, json_data); } else { - qDebug() << rawPacket << Qt::endl; + // requesting server is not allowed + Q_ASSERT(false); } } else if (type & TYPE_REPLY) { diff --git a/src/server/room.cpp b/src/server/room.cpp index 18189d5e..1137684b 100644 --- a/src/server/room.cpp +++ b/src/server/room.cpp @@ -8,6 +8,10 @@ Room::Room(Server* server) id = roomId; roomId++; this->server = server; + if (!isLobby()) { + connect(this, &Room::playerAdded, server->lobby(), &Room::removePlayer); + connect(this, &Room::playerRemoved, server->lobby(), &Room::addPlayer); + } } Room::~Room() @@ -72,7 +76,15 @@ void Room::setOwner(ServerPlayer *owner) void Room::addPlayer(ServerPlayer *player) { - players.insert(player->getId(), player); + if (!player) return; + players.insert(player->getUid(), player); + player->setRoom(this); + if (isLobby()) { + player->doNotify("enter_lobby", "{}"); + } else { + player->doNotify("enter_room", "{}"); + } + qDebug() << "Player #" << player->getUid() << " entered room"; emit playerAdded(player); } diff --git a/src/server/server.cpp b/src/server/server.cpp index c08906fb..5ea9f5ac 100644 --- a/src/server/server.cpp +++ b/src/server/server.cpp @@ -22,6 +22,7 @@ Server::Server(QObject* parent) L = CreateLuaState(); DoLuaScript(L, "lua/freekill.lua"); + DoLuaScript(L, "lua/server/server.lua"); } Server::~Server() @@ -41,13 +42,11 @@ void Server::createRoom(ServerPlayer* owner, const QString &name, uint capacity) room->setName(name); room->setCapacity(capacity); room->setOwner(owner); - // TODO - // room->addPlayer(owner); + room->addPlayer(owner); rooms.insert(room->getId(), room); #ifdef QT_DEBUG qDebug() << "Room #" << room->getId() << " created."; #endif - emit roomCreated(room); } Room *Server::findRoom(uint id) const @@ -75,13 +74,14 @@ void Server::processNewConnection(ClientSocket* client) // version check, file check, ban IP, reconnect, etc ServerPlayer *player = new ServerPlayer(lobby()); player->setSocket(client); + players.insert(player->getUid(), player); #ifdef QT_DEBUG qDebug() << "ServerPlayer #" << player->getUid() << "connected."; qDebug() << "His address is " << client->peerAddress(); #endif - player->doNotify("enter_lobby", "{}"); - + //player->doNotify("enter_lobby", "{}"); + lobby()->addPlayer(player); } void Server::onRoomAbandoned() diff --git a/src/ui/qmlbackend.cpp b/src/ui/qmlbackend.cpp index b95ebb6c..f9a294be 100644 --- a/src/ui/qmlbackend.cpp +++ b/src/ui/qmlbackend.cpp @@ -13,10 +13,13 @@ QmlBackend::QmlBackend(QObject* parent) void QmlBackend::startServer(ushort port) { - class Server *server = new class Server(this); - if (!server->listen(QHostAddress::Any, port)) { - server->deleteLater(); - emit notifyUI("error_msg", tr("Cannot start server!")); + if (!ServerInstance) { + class Server *server = new class Server(this); + + if (!server->listen(QHostAddress::Any, port)) { + server->deleteLater(); + emit notifyUI("error_msg", tr("Cannot start server!")); + } } } @@ -50,3 +53,8 @@ void QmlBackend::notifyServer(const QString& command, const QString& json_data) { ClientInstance->notifyServer(command, json_data); } + +void QmlBackend::quitLobby() +{ + delete ClientInstance; +} diff --git a/src/ui/qmlbackend.h b/src/ui/qmlbackend.h index 7eae0774..0e7f5373 100644 --- a/src/ui/qmlbackend.h +++ b/src/ui/qmlbackend.h @@ -31,6 +31,9 @@ public slots: void replyToServer(const QString &command, const QString &json_data); void notifyServer(const QString &command, const QString &json_data); + // Lobby + void quitLobby(); + private: WindowType type; };