parent
0033cd6c07
commit
5843442f98
|
@ -2482,6 +2482,18 @@ function Room:useSkill(player, skill, effect_cb)
|
|||
end
|
||||
end
|
||||
|
||||
---@param room Room
|
||||
local function shouldUpdateWinRate(room)
|
||||
if room.settings.gameMode == "heg_mode" then return false end
|
||||
if room.settings.gameMode == "aaa_role_mode" and #room.players < 5 then
|
||||
return false
|
||||
end
|
||||
for _, p in ipairs(room.players) do
|
||||
if p.id < 0 then return false end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
--- 结束一局游戏。
|
||||
---@param winner string @ 获胜的身份,空字符串表示平局
|
||||
function Room:gameOver(winner)
|
||||
|
@ -2494,6 +2506,24 @@ function Room:gameOver(winner)
|
|||
end
|
||||
self:doBroadcastNotify("GameOver", winner)
|
||||
|
||||
if shouldUpdateWinRate(self) then
|
||||
for _, p in ipairs(self.players) do
|
||||
local id = p.id
|
||||
local general = p.general
|
||||
local mode = self.settings.gameMode
|
||||
|
||||
if p.id > 0 then
|
||||
if table.contains(winner:split("+"), p.role) then
|
||||
self.room:updateWinRate(id, general, mode, 1)
|
||||
elseif winner == "" then
|
||||
self.room:updateWinRate(id, general, mode, 3)
|
||||
else
|
||||
self.room:updateWinRate(id, general, mode, 2)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self.room:gameOver()
|
||||
coroutine.yield("__handleRequest")
|
||||
end
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-3.0-or-later */
|
||||
|
||||
CREATE TABLE packages (
|
||||
CREATE TABLE IF NOT EXISTS packages (
|
||||
name VARCHAR(128),
|
||||
url VARCHAR(255),
|
||||
hash CHAR(40),
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
/* SPDX-License-Identifier: GPL-3.0-or-later */
|
||||
-- SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
CREATE TABLE userinfo (
|
||||
-- 用户基本信息
|
||||
|
||||
CREATE TABLE IF NOT EXISTS userinfo (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name VARCHAR(255),
|
||||
password CHAR(64),
|
||||
|
@ -10,6 +12,40 @@ CREATE TABLE userinfo (
|
|||
banned BOOLEAN
|
||||
);
|
||||
|
||||
CREATE TABLE banip (
|
||||
CREATE TABLE IF NOT EXISTS banip (
|
||||
ip VARCHAR(64)
|
||||
);
|
||||
|
||||
-- 胜率相关
|
||||
|
||||
CREATE TABLE IF NOT EXISTS winRate (
|
||||
id INTEGER,
|
||||
general VARCHAR(20),
|
||||
mode VARCHAR(16),
|
||||
win INTEGER,
|
||||
lose INTEGER,
|
||||
draw INTEGER,
|
||||
PRIMARY KEY (id, general, mode)
|
||||
);
|
||||
|
||||
CREATE VIEW IF NOT EXISTS playerWinRate AS
|
||||
SELECT winRate.id, name, mode,
|
||||
SUM(win) AS 'win',
|
||||
SUM(lose) AS 'lose',
|
||||
SUM(draw) AS 'draw',
|
||||
SUM(win + lose + draw) AS 'total',
|
||||
ROUND(SUM(win) * 1.0 / (SUM(win + lose + draw) * 1.0) * 100, 2)
|
||||
AS 'winRate'
|
||||
FROM winRate, userinfo
|
||||
WHERE winRate.id = userinfo.id
|
||||
GROUP BY winRate.id, mode;
|
||||
|
||||
CREATE VIEW IF NOT EXISTS generalWinRate AS
|
||||
SELECT general, mode,
|
||||
SUM(win) AS 'win',
|
||||
SUM(lose) AS 'lose',
|
||||
SUM(draw) AS 'draw',
|
||||
SUM(win + lose + draw) AS 'total',
|
||||
ROUND(SUM(win) * 1.0 / (SUM(win + lose + draw) * 1.0) * 100, 2)
|
||||
AS 'winRate'
|
||||
FROM winRate GROUP BY general, mode;
|
||||
|
|
|
@ -63,14 +63,15 @@ void Dumpstack(lua_State *L) {
|
|||
sqlite3 *OpenDatabase(const QString &filename, const QString &initSql) {
|
||||
sqlite3 *ret;
|
||||
int rc;
|
||||
if (!QFile::exists(filename)) {
|
||||
QFile file(initSql);
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
qFatal("cannot open %s. Quit now.", initSql.toUtf8().data());
|
||||
qApp->exit(1);
|
||||
}
|
||||
|
||||
QTextStream in(&file);
|
||||
QFile file(initSql);
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
qFatal("cannot open %s. Quit now.", initSql.toUtf8().data());
|
||||
qApp->exit(1);
|
||||
}
|
||||
QTextStream in(&file);
|
||||
|
||||
if (!QFile::exists(filename)) {
|
||||
char *err_msg;
|
||||
sqlite3_open(filename.toLatin1().data(), &ret);
|
||||
rc = sqlite3_exec(ret, in.readAll().toLatin1().data(), nullptr, nullptr,
|
||||
|
@ -89,10 +90,26 @@ sqlite3 *OpenDatabase(const QString &filename, const QString &initSql) {
|
|||
sqlite3_close(ret);
|
||||
qApp->exit(1);
|
||||
}
|
||||
|
||||
char *err_msg;
|
||||
rc = sqlite3_exec(ret, in.readAll().toLatin1().data(), nullptr, nullptr,
|
||||
&err_msg);
|
||||
|
||||
if (rc != SQLITE_OK) {
|
||||
qCritical() << "sqlite error:" << err_msg;
|
||||
sqlite3_free(err_msg);
|
||||
sqlite3_close(ret);
|
||||
qApp->exit(1);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CheckSqlString(const QString &str) {
|
||||
static const QRegularExpression exp("['\";#]+|(--)|(/\\*)|(\\*/)|(--\\+)");
|
||||
return (!exp.match(str).hasMatch() && !str.isEmpty());
|
||||
}
|
||||
|
||||
// callback for handling SELECT expression
|
||||
static int callback(void *jsonDoc, int argc, char **argv, char **cols) {
|
||||
QJsonObject obj;
|
||||
|
|
|
@ -9,6 +9,7 @@ lua_State *CreateLuaState();
|
|||
bool DoLuaScript(lua_State *L, const char *script);
|
||||
|
||||
sqlite3 *OpenDatabase(const QString &filename = "./server/users.db", const QString &initSql = "./server/init.sql");
|
||||
bool CheckSqlString(const QString &str);
|
||||
QJsonArray SelectFromDatabase(sqlite3 *db, const QString &sql);
|
||||
// For Lua
|
||||
QString SelectFromDb(sqlite3 *db, const QString &sql);
|
||||
|
|
|
@ -155,8 +155,8 @@ void Router::handlePacket(const QByteArray &rawPacket) {
|
|||
const QString &jsonData) {
|
||||
auto arr = String2Json(jsonData).array();
|
||||
auto avatar = arr[0].toString();
|
||||
static QRegularExpression nameExp("['\";#]+|(--)|(/\\*)|(\\*/)|(--\\+)");
|
||||
if (!nameExp.match(avatar).hasMatch()) {
|
||||
|
||||
if (CheckSqlString(avatar)) {
|
||||
auto sql = QString("UPDATE userinfo SET avatar='%1' WHERE id=%2;")
|
||||
.arg(avatar)
|
||||
.arg(sender->getId());
|
||||
|
|
|
@ -302,9 +302,68 @@ void Room::chat(ServerPlayer *sender, const QString &jsonData) {
|
|||
doBroadcastNotify(observers, "Chat", json);
|
||||
}
|
||||
|
||||
|
||||
qInfo("[Chat] %s: %s", sender->getScreenName().toUtf8().constData(),
|
||||
doc["msg"].toString().toUtf8().constData());
|
||||
doc["msg"].toString().toUtf8().constData());
|
||||
}
|
||||
|
||||
void Room::updateWinRate(int id, const QString &general, const QString &mode,
|
||||
int game_result) {
|
||||
static const QString findWinRate =
|
||||
QString("SELECT win, lose, draw "
|
||||
"FROM winRate WHERE id = %1 and general = '%2' and mode = '%3';");
|
||||
|
||||
static const QString updateRate =
|
||||
QString("UPDATE winRate "
|
||||
"SET win = %4, lose = %5, draw = %6 "
|
||||
"WHERE id = %1 and general = '%2' and mode = '%3';");
|
||||
|
||||
static const QString insertRate =
|
||||
QString("INSERT INTO winRate "
|
||||
"(id, general, mode, win, lose, draw) "
|
||||
"VALUES (%1, '%2', '%3', %4, %5, %6);");
|
||||
|
||||
if (!CheckSqlString(general))
|
||||
return;
|
||||
if (!CheckSqlString(mode))
|
||||
return;
|
||||
|
||||
int win = 0;
|
||||
int lose = 0;
|
||||
int draw = 0;
|
||||
|
||||
switch (game_result) {
|
||||
case 1:
|
||||
win++;
|
||||
break;
|
||||
case 2:
|
||||
lose++;
|
||||
break;
|
||||
case 3:
|
||||
draw++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
QJsonArray result =
|
||||
SelectFromDatabase(server->getDatabase(),
|
||||
findWinRate.arg(QString::number(id), general, mode));
|
||||
|
||||
if (result.isEmpty()) {
|
||||
ExecSQL(server->getDatabase(),
|
||||
insertRate.arg(QString::number(id), general, mode,
|
||||
QString::number(win), QString::number(lose),
|
||||
QString::number(draw)));
|
||||
} else {
|
||||
auto obj = result[0].toObject();
|
||||
win += obj["win"].toString().toInt();
|
||||
lose += obj["lose"].toString().toInt();
|
||||
draw += obj["draw"].toString().toInt();
|
||||
ExecSQL(server->getDatabase(),
|
||||
updateRate.arg(QString::number(id), general, mode,
|
||||
QString::number(win), QString::number(lose),
|
||||
QString::number(draw)));
|
||||
}
|
||||
}
|
||||
|
||||
void Room::gameOver() {
|
||||
|
@ -324,7 +383,8 @@ void Room::gameOver() {
|
|||
}
|
||||
|
||||
QString Room::fetchRequest() {
|
||||
if (!gameStarted) return "";
|
||||
if (!gameStarted)
|
||||
return "";
|
||||
request_queue_mutex.lock();
|
||||
QString ret = "";
|
||||
if (!request_queue.isEmpty()) {
|
||||
|
@ -335,7 +395,8 @@ QString Room::fetchRequest() {
|
|||
}
|
||||
|
||||
void Room::pushRequest(const QString &req) {
|
||||
if (!gameStarted) return;
|
||||
if (!gameStarted)
|
||||
return;
|
||||
request_queue_mutex.lock();
|
||||
request_queue.enqueue(req);
|
||||
request_queue_mutex.unlock();
|
||||
|
|
|
@ -52,6 +52,8 @@ class Room : public QThread {
|
|||
const QString &command, const QString &jsonData);
|
||||
void chat(ServerPlayer *sender, const QString &jsonData);
|
||||
|
||||
void updateWinRate(int id, const QString &general, const QString &mode,
|
||||
int result);
|
||||
void gameOver();
|
||||
|
||||
void initLua();
|
||||
|
|
|
@ -220,10 +220,6 @@ void Server::processRequest(const QByteArray &msg) {
|
|||
void Server::handleNameAndPassword(ClientSocket *client, const QString &name,
|
||||
const QString &password,
|
||||
const QString &md5_str) {
|
||||
// First check the name and password
|
||||
// Matches a string that does not contain special characters
|
||||
static QRegularExpression nameExp("['\";#]+|(--)|(/\\*)|(\\*/)|(--\\+)");
|
||||
|
||||
auto encryted_pw = QByteArray::fromBase64(password.toLatin1());
|
||||
unsigned char buf[4096] = {0};
|
||||
RSA_private_decrypt(RSA_size(rsa), (const unsigned char *)encryted_pw.data(),
|
||||
|
@ -263,7 +259,7 @@ void Server::handleNameAndPassword(ClientSocket *client, const QString &name,
|
|||
QJsonArray result;
|
||||
QJsonObject obj;
|
||||
|
||||
if (!nameExp.match(name).hasMatch() && !name.isEmpty()) {
|
||||
if (CheckSqlString(name)) {
|
||||
// Then we check the database,
|
||||
QString sql_find = QString("SELECT * FROM userinfo \
|
||||
WHERE name='%1';")
|
||||
|
@ -311,7 +307,7 @@ void Server::handleNameAndPassword(ClientSocket *client, const QString &name,
|
|||
player->alive = true;
|
||||
client->disconnect(this);
|
||||
broadcast("ServerMessage",
|
||||
tr("%1 backed").arg(player->getScreenName()));
|
||||
tr("%1 backed").arg(player->getScreenName()));
|
||||
room->pushRequest(QString("%1,reconnect").arg(id));
|
||||
return;
|
||||
} else {
|
||||
|
|
|
@ -51,6 +51,8 @@ public:
|
|||
const QString &jsonData
|
||||
);
|
||||
|
||||
void updateWinRate(int id, const QString &general, const QString &mode,
|
||||
int result);
|
||||
void gameOver();
|
||||
|
||||
LuaFunction startGame;
|
||||
|
|
Loading…
Reference in New Issue