parent
46176e2477
commit
f1820bb07b
|
@ -538,13 +538,20 @@ fk.client_callback["SetPlayerMark"] = function(jsonData)
|
|||
end
|
||||
|
||||
fk.client_callback["Chat"] = function(jsonData)
|
||||
-- jsonData: { int type, string msg }
|
||||
-- jsonData: { int type, int sender, string msg }
|
||||
local data = json.decode(jsonData)
|
||||
local p = ClientInstance:getPlayerById(data.type)
|
||||
if data.type == 1 then
|
||||
data.general = ""
|
||||
data.time = os.date("%H:%M:%S")
|
||||
ClientInstance:notifyUI("Chat", json.encode(data))
|
||||
return
|
||||
end
|
||||
|
||||
local p = ClientInstance:getPlayerById(data.sender)
|
||||
-- TODO: observer chatting
|
||||
if not p then
|
||||
for _, pl in ipairs(ClientInstance.observers) do
|
||||
if pl.id == data.type then
|
||||
if pl.id == data.sender then
|
||||
p = pl; break
|
||||
end
|
||||
end
|
||||
|
@ -618,6 +625,10 @@ fk.client_callback["RemoveVirtualEquip"] = function(jsonData)
|
|||
player:removeVirtualEquip(data.id)
|
||||
end
|
||||
|
||||
fk.client_callback["Heartbeat"] = function()
|
||||
ClientInstance.client:notifyServer("Heartbeat", "")
|
||||
end
|
||||
|
||||
-- Create ClientInstance (used by Lua)
|
||||
ClientInstance = Client:new()
|
||||
dofile "lua/client/client_util.lua"
|
||||
|
|
|
@ -28,6 +28,8 @@ Fk:loadTranslationTable{
|
|||
["General Packages"] = "武将拓展包",
|
||||
["Card Packages"] = "卡牌拓展包",
|
||||
|
||||
["$OnlineInfo"] = "大厅人数:%1,总在线人数:%2",
|
||||
|
||||
["Generals Overview"] = "武将一览",
|
||||
["Cards Overview"] = "卡牌一览",
|
||||
["Scenarios Overview"] = "玩法一览",
|
||||
|
|
Before Width: | Height: | Size: 406 B After Width: | Height: | Size: 406 B |
11
qml/Logic.js
11
qml/Logic.js
|
@ -101,11 +101,20 @@ callbacks["UpdateRoomList"] = function(jsonData) {
|
|||
});
|
||||
}
|
||||
|
||||
callbacks["UpdatePlayerNum"] = (j) => {
|
||||
let current = mainStack.currentItem; // should be lobby
|
||||
let data = JSON.parse(j);
|
||||
let l = data[0];
|
||||
let s = data[1];
|
||||
current.lobbyPlayerNum = l;
|
||||
current.serverPlayerNum = s;
|
||||
}
|
||||
|
||||
callbacks["Chat"] = function(jsonData) {
|
||||
// jsonData: { string userName, string general, string time, string msg }
|
||||
let current = mainStack.currentItem; // lobby(TODO) or room
|
||||
let data = JSON.parse(jsonData);
|
||||
let pid = data.type;
|
||||
let pid = data.sender;
|
||||
let userName = data.userName;
|
||||
let general = Backend.translate(data.general);
|
||||
let time = data.time;
|
||||
|
|
|
@ -44,7 +44,7 @@ Rectangle {
|
|||
ClientInstance.notifyServer(
|
||||
"Chat",
|
||||
JSON.stringify({
|
||||
type: isLobby,
|
||||
type: isLobby ? 1 : 2,
|
||||
msg: text
|
||||
})
|
||||
);
|
||||
|
|
|
@ -3,6 +3,7 @@ import QtQuick.Controls
|
|||
import QtQuick.Window
|
||||
import QtQuick.Layouts
|
||||
import "LobbyElement"
|
||||
import "Common"
|
||||
import "Logic.js" as Logic
|
||||
|
||||
Item {
|
||||
|
@ -107,69 +108,6 @@ Item {
|
|||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
GridLayout {
|
||||
flow: GridLayout.TopToBottom
|
||||
rows: 4
|
||||
TileButton {
|
||||
iconSource: "configure"
|
||||
text: Backend.translate("Edit Profile")
|
||||
onClicked: {
|
||||
lobby_dialog.source = "LobbyElement/EditProfile.qml";
|
||||
lobby_drawer.open();
|
||||
}
|
||||
}
|
||||
TileButton {
|
||||
iconSource: "create_room"
|
||||
text: Backend.translate("Create Room")
|
||||
onClicked: {
|
||||
lobby_dialog.source = "LobbyElement/CreateRoom.qml";
|
||||
lobby_drawer.open();
|
||||
config.observing = false;
|
||||
}
|
||||
}
|
||||
TileButton {
|
||||
iconSource: "general_overview"
|
||||
text: Backend.translate("Generals Overview")
|
||||
onClicked: {
|
||||
mainStack.push(mainWindow.generalsOverviewPage);
|
||||
mainStack.currentItem.loadPackages();
|
||||
}
|
||||
}
|
||||
TileButton {
|
||||
iconSource: "card_overview"
|
||||
text: Backend.translate("Cards Overview")
|
||||
onClicked: {
|
||||
mainStack.push(mainWindow.cardsOverviewPage);
|
||||
mainStack.currentItem.loadPackages();
|
||||
}
|
||||
}
|
||||
TileButton {
|
||||
iconSource: "rule_summary"
|
||||
text: Backend.translate("Scenarios Overview")
|
||||
}
|
||||
TileButton {
|
||||
iconSource: "replay"
|
||||
text: Backend.translate("Replay")
|
||||
}
|
||||
TileButton {
|
||||
iconSource: "about"
|
||||
text: Backend.translate("About")
|
||||
onClicked: {
|
||||
mainStack.push(mainWindow.aboutPage);
|
||||
}
|
||||
}
|
||||
TileButton {
|
||||
iconSource: "quit"
|
||||
text: Backend.translate("Exit Lobby")
|
||||
onClicked: {
|
||||
toast.show("Goodbye.");
|
||||
Backend.quitLobby();
|
||||
mainStack.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
Button {
|
||||
|
@ -257,6 +195,49 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
property int lobbyPlayerNum: 0
|
||||
property int serverPlayerNum: 0
|
||||
|
||||
function updateOnlineInfo() {
|
||||
}
|
||||
|
||||
onLobbyPlayerNumChanged: updateOnlineInfo();
|
||||
onServerPlayerNumChanged: updateOnlineInfo();
|
||||
|
||||
Rectangle {
|
||||
id: info
|
||||
color: "#88EEEEEE"
|
||||
width: childrenRect.width + 8
|
||||
height: childrenRect.height + 4
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
radius: 4
|
||||
|
||||
Text {
|
||||
x: 4; y: 2
|
||||
font.pixelSize: 16
|
||||
text: Backend.translate("$OnlineInfo")
|
||||
.arg(lobbyPlayerNum).arg(serverPlayerNum) + "\n"
|
||||
+ "Powered by FreeKill " + FkVersion
|
||||
}
|
||||
}
|
||||
|
||||
ChatBox {
|
||||
id: lobbyChat
|
||||
anchors.bottom: info.top
|
||||
width: info.width
|
||||
height: root.height * 0.6
|
||||
isLobby: true
|
||||
color: "#88EEEEEE"
|
||||
radius: 4
|
||||
}
|
||||
|
||||
function addToChat(pid, raw, msg) {
|
||||
if (raw.type !== 1) return;
|
||||
lobbyChat.append(msg);
|
||||
toast.show("<b>" + raw.userName + "</b>: " + raw.msg);
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
toast.show(Backend.translate("$WelcomeToLobby"));
|
||||
}
|
||||
|
|
|
@ -669,6 +669,7 @@ Item {
|
|||
}
|
||||
|
||||
function addToChat(pid, raw, msg) {
|
||||
if (raw.type === 1) return;
|
||||
chat.append(msg);
|
||||
let photo = Logic.getPhotoOrSelf(pid);
|
||||
if (photo === undefined)
|
||||
|
|
|
@ -162,7 +162,7 @@ void Router::handlePacket(const QByteArray& rawPacket)
|
|||
lobby_actions["UpdateAvatar"] = [](ServerPlayer *sender, const QString &jsonData){
|
||||
auto arr = String2Json(jsonData).array();
|
||||
auto avatar = arr[0].toString();
|
||||
static QRegularExpression nameExp("[\\000-\\057\\072-\\100\\133-\\140\\173-\\177]");
|
||||
static QRegularExpression nameExp("['\";#]+|(--)|(/\\*)|(\\*/)|(--\\+)");
|
||||
if (!nameExp.match(avatar).hasMatch()) {
|
||||
auto sql = QString("UPDATE userinfo SET avatar='%1' WHERE id=%2;")
|
||||
.arg(avatar).arg(sender->getId());
|
||||
|
@ -238,6 +238,10 @@ void Router::handlePacket(const QByteArray& rawPacket)
|
|||
else
|
||||
{
|
||||
ServerPlayer *player = qobject_cast<ServerPlayer *>(parent());
|
||||
if (command == "Heartbeat") {
|
||||
player->alive = true;
|
||||
return;
|
||||
}
|
||||
|
||||
Room *room = player->getRoom();
|
||||
if (room->isLobby() && lobby_actions.contains(command))
|
||||
|
|
|
@ -314,9 +314,11 @@ void Room::doBroadcastNotify(const QList<ServerPlayer *> targets,
|
|||
void Room::chat(ServerPlayer *sender, const QString &jsonData) {
|
||||
auto doc = String2Json(jsonData).object();
|
||||
auto type = doc["type"].toInt();
|
||||
doc["type"] = sender->getId();
|
||||
doc["sender"] = sender->getId();
|
||||
if (type == 1) {
|
||||
// TODO: server chatting
|
||||
doc["userName"] = sender->getScreenName();
|
||||
auto json = QJsonDocument(doc).toJson(QJsonDocument::Compact);
|
||||
doBroadcastNotify(players, "Chat", json);
|
||||
} else {
|
||||
auto json = QJsonDocument(doc).toJson(QJsonDocument::Compact);
|
||||
doBroadcastNotify(players, "Chat", json);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "server.h"
|
||||
#include "player.h"
|
||||
#include "server_socket.h"
|
||||
#include "client_socket.h"
|
||||
#include "room.h"
|
||||
|
@ -7,6 +8,7 @@
|
|||
#include "util.h"
|
||||
#include "parser.h"
|
||||
#include "packman.h"
|
||||
#include <qjsonarray.h>
|
||||
|
||||
Server *ServerInstance;
|
||||
|
||||
|
@ -33,6 +35,28 @@ Server::Server(QObject* parent)
|
|||
createRoom(nullptr, "Lobby", INT32_MAX);
|
||||
connect(lobby(), &Room::playerAdded, this, &Server::updateRoomList);
|
||||
connect(lobby(), &Room::playerRemoved, this, &Server::updateRoomList);
|
||||
|
||||
auto heartbeatThread = QThread::create([=](){
|
||||
while (true) {
|
||||
foreach (auto p, this->players.values()) {
|
||||
if (p->getState() == Player::Online) {
|
||||
p->alive = false;
|
||||
p->doNotify("Heartbeat", "");
|
||||
}
|
||||
}
|
||||
|
||||
// wait for reply
|
||||
QThread::sleep(5);
|
||||
|
||||
foreach (auto p, this->players.values()) {
|
||||
if (p->getState() == Player::Online && !p->alive) {
|
||||
p->kicked();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
heartbeatThread->setObjectName("Heartbeat");
|
||||
heartbeatThread->start();
|
||||
}
|
||||
|
||||
Server::~Server()
|
||||
|
@ -119,6 +143,15 @@ void Server::updateRoomList()
|
|||
"UpdateRoomList",
|
||||
QString(jsonData)
|
||||
);
|
||||
|
||||
lobby()->doBroadcastNotify(
|
||||
lobby()->getPlayers(),
|
||||
"UpdatePlayerNum",
|
||||
QString(JsonArray2Bytes(QJsonArray({
|
||||
lobby()->getPlayers().length(),
|
||||
this->players.count(),
|
||||
})))
|
||||
);
|
||||
}
|
||||
|
||||
sqlite3 *Server::getDatabase() {
|
||||
|
@ -206,7 +239,7 @@ void Server::handleNameAndPassword(ClientSocket *client, const QString& name, co
|
|||
{
|
||||
// First check the name and password
|
||||
// Matches a string that does not contain special characters
|
||||
static QRegularExpression nameExp("[\\000-\\057\\072-\\100\\133-\\140\\173-\\177]");
|
||||
static QRegularExpression nameExp("['\";#]+|(--)|(/\\*)|(\\*/)|(--\\+)");
|
||||
|
||||
auto encryted_pw = QByteArray::fromBase64(password.toLatin1());
|
||||
unsigned char buf[4096] = {0};
|
||||
|
|
|
@ -11,6 +11,9 @@ ServerPlayer::ServerPlayer(Room *room)
|
|||
setState(Player::Online);
|
||||
this->room = room;
|
||||
server = room->getServer();
|
||||
connect(this, &ServerPlayer::kicked, this, &ServerPlayer::kick);
|
||||
|
||||
alive = true;
|
||||
}
|
||||
|
||||
ServerPlayer::~ServerPlayer()
|
||||
|
@ -112,3 +115,10 @@ void ServerPlayer::prepareForRequest(const QString& command, const QString& data
|
|||
requestCommand = command;
|
||||
requestData = data;
|
||||
}
|
||||
|
||||
void ServerPlayer::kick() {
|
||||
if (socket != nullptr) {
|
||||
socket->disconnectFromHost();
|
||||
}
|
||||
setSocket(nullptr);
|
||||
}
|
||||
|
|
|
@ -33,8 +33,12 @@ public:
|
|||
void prepareForRequest(const QString &command,
|
||||
const QString &data);
|
||||
|
||||
volatile bool alive; // For heartbeat
|
||||
void kick();
|
||||
|
||||
signals:
|
||||
void disconnected();
|
||||
void kicked();
|
||||
|
||||
private:
|
||||
ClientSocket *socket; // socket for communicating with client
|
||||
|
|
|
@ -27,6 +27,7 @@ void Shell::helpCommand(QStringList &) {
|
|||
qInfo("%s: Enable a package.", "enable");
|
||||
qInfo("%s: Disable a package.", "disable");
|
||||
qInfo("%s: Upgrade a package.", "upgrade");
|
||||
qInfo("%s: Kick a player by his id.", "kick");
|
||||
qInfo("For more commands, check the documentation.");
|
||||
}
|
||||
|
||||
|
@ -115,6 +116,24 @@ void Shell::lspkgCommand(QStringList &) {
|
|||
}
|
||||
}
|
||||
|
||||
void Shell::kickCommand(QStringList &list) {
|
||||
if (list.isEmpty()) {
|
||||
qWarning("The 'kick' command needs a player id.");
|
||||
return;
|
||||
}
|
||||
|
||||
auto pid = list[0];
|
||||
bool ok;
|
||||
int id = pid.toInt(&ok);
|
||||
if (!ok) return;
|
||||
|
||||
auto p = ServerInstance->findPlayer(id);
|
||||
if (p) {
|
||||
p->kicked();
|
||||
qInfo("Success");
|
||||
}
|
||||
}
|
||||
|
||||
Shell::Shell() {
|
||||
setObjectName("Shell");
|
||||
signal(SIGINT, sigintHandler);
|
||||
|
@ -131,6 +150,7 @@ Shell::Shell() {
|
|||
handlers["lspkg"] = &Shell::lspkgCommand;
|
||||
handlers["enable"] = &Shell::enableCommand;
|
||||
handlers["disable"] = &Shell::disableCommand;
|
||||
handlers["kick"] = &Shell::kickCommand;
|
||||
}
|
||||
handler_map = handlers;
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ private:
|
|||
void lspkgCommand(QStringList &);
|
||||
void enableCommand(QStringList &);
|
||||
void disableCommand(QStringList &);
|
||||
void kickCommand(QStringList &);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue