From 0e51614588e0e5392fb3ecb1d278b8bdaa52d33b Mon Sep 17 00:00:00 2001 From: notify Date: Tue, 18 Apr 2023 23:26:15 +0800 Subject: [PATCH] Observer chat (#125) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增旁观者聊天栏兼公告栏 增加服务端广播消息功能 修复单机启动失败时被心跳包卡死机的情况 修复发配音时undefined 聊天信息服务端回显 --- qml/Logic.js | 7 +++- qml/Pages/Danmaku.qml | 79 +++++++++++++++++++++++++++++++++++++++++++ qml/Pages/Lobby.qml | 11 +++++- qml/Pages/Room.qml | 25 +++++++++++--- src/server/room.cpp | 3 ++ src/server/server.cpp | 19 +++++++++-- src/server/server.h | 2 ++ src/server/shell.cpp | 13 ++++++- src/server/shell.h | 1 + 9 files changed, 151 insertions(+), 9 deletions(-) create mode 100644 qml/Pages/Danmaku.qml diff --git a/qml/Logic.js b/qml/Logic.js index 6f37e8d4..aba5fff0 100644 --- a/qml/Logic.js +++ b/qml/Logic.js @@ -121,7 +121,7 @@ callbacks["UpdatePlayerNum"] = (j) => { callbacks["Chat"] = function(jsonData) { // jsonData: { string userName, string general, string time, string msg } - let current = mainStack.currentItem; // lobby(TODO) or room + let current = mainStack.currentItem; // lobby or room let data = JSON.parse(jsonData); let pid = data.sender; let userName = data.userName; @@ -134,3 +134,8 @@ callbacks["Chat"] = function(jsonData) { else current.addToChat(pid, data, `[${time}] ${userName}(${general}): ${msg}`); } + +callbacks["ServerMessage"] = function(jsonData) { + let current = mainStack.currentItem; // lobby or room + current.sendDanmaku('[Server] ' + jsonData); +} diff --git a/qml/Pages/Danmaku.qml b/qml/Pages/Danmaku.qml new file mode 100644 index 00000000..1855a2c1 --- /dev/null +++ b/qml/Pages/Danmaku.qml @@ -0,0 +1,79 @@ +import QtQuick + +Item { + id: root + width: 900 + height: 20 + visible: false + property bool newTxtAvailable: true + property var stashedTxt: [] + property int currentRunning: 0 + + onNewTxtAvailableChanged: { + if (!newTxtAvailable || stashedTxt.length === 0) { + return; + } + let t = stashedTxt.splice(0, 1)[0]; + let obj = txtComponent.createObject(root, { text: t }); + obj.finished.connect(() => obj.destroy()); + obj.start(); + } + + onCurrentRunningChanged: { + visible = !!currentRunning; + } + + Rectangle { + anchors.fill: parent + color: "black" + opacity: 0.7 + } + + Component { + id: txtComponent + Text { + id: txt + color: "white" + font.pixelSize: 18 + font.family: fontLibian.name + textFormat: TextEdit.RichText + y: -1 + property bool changedAvail: false + signal finished() + + onXChanged: { + if (root.width - x - 40 > width && !changedAvail) { + root.newTxtAvailable = true; + changedAvail = true; + } + } + + PropertyAnimation on x { + id: txtAnim + running: false + from: root.width + to: -txt.width + duration: (root.width + txt.width) * 5 + + onFinished: { + root.currentRunning--; + txt.finished(); + } + } + + function start() { + root.newTxtAvailable = false; + root.currentRunning++; + txtAnim.start(); + } + } + } + + function sendLog(txt) { + root.stashedTxt.push(txt); + if (root.newTxtAvailable) { + root.newTxtAvailable = false; + root.newTxtAvailable = true; + } + } +} diff --git a/qml/Pages/Lobby.qml b/qml/Pages/Lobby.qml index 424c6cf4..68e5a489 100644 --- a/qml/Pages/Lobby.qml +++ b/qml/Pages/Lobby.qml @@ -234,10 +234,19 @@ Item { radius: 4 } + Danmaku { + id: danmaku + width: parent.width + } + function addToChat(pid, raw, msg) { if (raw.type !== 1) return; lobbyChat.append(msg); - toast.show("" + raw.userName + ": " + raw.msg); + danmaku.sendLog("" + raw.userName + ": " + raw.msg); + } + + function sendDanmaku(msg) { + danmaku.sendLog(msg); } Component.onCompleted: { diff --git a/qml/Pages/Room.qml b/qml/Pages/Room.qml index cd45c9a5..5a353216 100644 --- a/qml/Pages/Room.qml +++ b/qml/Pages/Room.qml @@ -625,6 +625,11 @@ Item { } } + Danmaku { + id: danmaku + width: parent.width + } + Shortcut { sequence: "T" onActivated: { @@ -677,12 +682,16 @@ Item { if (raw.type === 1) return; if (raw.msg.startsWith("$")) { - if (specialChat(pid, data, raw.msg.slice(1))) return; + if (specialChat(pid, raw, raw.msg.slice(1))) return; } chat.append(msg); let photo = Logic.getPhotoOrSelf(pid); - if (photo === undefined) + if (photo === undefined) { + let user = raw.userName; + let m = raw.msg; + danmaku.sendLog(`${user}: ${m}`); return; + } photo.chat(raw.msg); } @@ -720,8 +729,10 @@ Item { chat.append(`[${time}] ${userName}(${general}): ${m}`); let photo = Logic.getPhotoOrSelf(pid); - if (photo === undefined) + if (photo === undefined) { + danmaku.sendLog(`${userName}: ${m}`); return true; + } photo.chat(m); return true; @@ -743,8 +754,10 @@ Item { chat.append(`[${time}] ${userName}(${general}): ${m}`); let photo = Logic.getPhotoOrSelf(pid); - if (photo === undefined) + if (photo === undefined) { + danmaku.sendLog(`${userName}: ${m}`); return true; + } photo.chat(m); return true; @@ -757,6 +770,10 @@ Item { log.append(msg); } + function sendDanmaku(msg) { + danmaku.sendLog(msg); + } + function showDistance(show) { for (let i = 0; i < photoModel.count; i++) { let item = photos.itemAt(i); diff --git a/src/server/room.cpp b/src/server/room.cpp index 0b40a3f3..c32c8624 100644 --- a/src/server/room.cpp +++ b/src/server/room.cpp @@ -295,6 +295,9 @@ void Room::chat(ServerPlayer *sender, const QString &jsonData) { doBroadcastNotify(players, "Chat", json); doBroadcastNotify(observers, "Chat", json); } + + qInfo("[Chat] %s: %s", sender->getScreenName().toUtf8().constData(), + doc["msg"].toString().toUtf8().constData()); } void Room::gameOver() { diff --git a/src/server/server.cpp b/src/server/server.cpp index 3f0e6618..471cf43b 100644 --- a/src/server/server.cpp +++ b/src/server/server.cpp @@ -3,6 +3,7 @@ #include "server.h" #include +#include #include "client_socket.h" #include "packman.h" @@ -49,7 +50,12 @@ Server::Server(QObject *parent) : QObject(parent) { } } - QThread::sleep(20); + for (int i = 0; i < 10; i++) { + if (!this->isListening) { + return; + } + QThread::sleep(2); + } foreach (auto p, this->players.values()) { if (p->getState() == Player::Online && !p->alive) { @@ -58,6 +64,7 @@ Server::Server(QObject *parent) : QObject(parent) { } } }); + heartbeatThread->setParent(this); heartbeatThread->setObjectName("Heartbeat"); heartbeatThread->start(); } @@ -70,7 +77,9 @@ Server::~Server() { } bool Server::listen(const QHostAddress &address, ushort port) { - return server->listen(address, port); + bool ret = server->listen(address, port); + isListening = ret; + return ret; } void Server::createRoom(ServerPlayer *owner, const QString &name, int capacity, @@ -139,6 +148,12 @@ void Server::updateRoomList() { sqlite3 *Server::getDatabase() { return db; } +void Server::broadcast(const QString &command, const QString &jsonData) { + foreach (ServerPlayer *p, players.values()) { + p->doNotify(command, jsonData); + } +} + void Server::processNewConnection(ClientSocket *client) { qInfo() << client->peerAddress() << "connected"; // version check, file check, ban IP, reconnect, etc diff --git a/src/server/server.h b/src/server/server.h index 89c9cecf..4b7b789a 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -33,6 +33,8 @@ public: sqlite3 *getDatabase(); + void broadcast(const QString &command, const QString &jsonData); + bool isListening; signals: void roomCreated(Room *room); void playerAdded(ServerPlayer *player); diff --git a/src/server/shell.cpp b/src/server/shell.cpp index a62314d1..693f5f91 100644 --- a/src/server/shell.cpp +++ b/src/server/shell.cpp @@ -30,6 +30,7 @@ void Shell::helpCommand(QStringList &) { qInfo("%s: Disable a package.", "disable"); qInfo("%s: Upgrade a package.", "upgrade"); qInfo("%s: Kick a player by his id.", "kick"); + qInfo("%s: Broadcast message.", "msg"); qInfo("For more commands, check the documentation."); } @@ -133,10 +134,19 @@ void Shell::kickCommand(QStringList &list) { auto p = ServerInstance->findPlayer(id); if (p) { p->kicked(); - qInfo("Success"); } } +void Shell::msgCommand(QStringList &list) { + if (list.isEmpty()) { + qWarning("The 'msg' command needs message body."); + return; + } + + auto msg = list.join(' '); + ServerInstance->broadcast("ServerMessage", msg); +} + Shell::Shell() { setObjectName("Shell"); signal(SIGINT, sigintHandler); @@ -154,6 +164,7 @@ Shell::Shell() { handlers["enable"] = &Shell::enableCommand; handlers["disable"] = &Shell::disableCommand; handlers["kick"] = &Shell::kickCommand; + handlers["msg"] = &Shell::msgCommand; } handler_map = handlers; } diff --git a/src/server/shell.h b/src/server/shell.h index 4c40e240..cbe1dbee 100644 --- a/src/server/shell.h +++ b/src/server/shell.h @@ -39,6 +39,7 @@ private: void enableCommand(QStringList &); void disableCommand(QStringList &); void kickCommand(QStringList &); + void msgCommand(QStringList &); }; #endif