diff --git a/Fk/Logic.js b/Fk/Logic.js index 5e2ad89d..4fef708c 100644 --- a/Fk/Logic.js +++ b/Fk/Logic.js @@ -143,14 +143,12 @@ callbacks["UpdateRoomList"] = (jsonData) => { const current = mainStack.currentItem; // should be lobby if (mainStack.depth === 2) { current.roomModel.clear(); - JSON.parse(jsonData).forEach(function (room) { + JSON.parse(jsonData).forEach(room => { + const [roomId, roomName, gameMode, playerNum, capacity, hasPassword, + outdated] = room; current.roomModel.append({ - roomId: room[0], - roomName: room[1], - gameMode: room[2], - playerNum: room[3], - capacity: room[4], - hasPassword: room[5] ? true : false, + roomId, roomName, gameMode, playerNum, capacity, + hasPassword, outdated, }); }); } diff --git a/Fk/Pages/Lobby.qml b/Fk/Pages/Lobby.qml index 8da9162c..9c5e071a 100644 --- a/Fk/Pages/Lobby.qml +++ b/Fk/Pages/Lobby.qml @@ -64,7 +64,13 @@ Item { Text { horizontalAlignment: Text.AlignLeft Layout.fillWidth: true - text: roomName + text: { + let ret = roomName; + if (outdated) { + ret = '' + ret + ''; + } + return ret; + } font.pixelSize: 20 elide: Label.ElideRight } @@ -94,7 +100,7 @@ Item { text: (playerNum < capacity) ? luatr("Enter") : luatr("Observe") - enabled: !opTimer.running + enabled: !opTimer.running && !outdated onClicked: { opTimer.start(); diff --git a/lang/zh_CN.ts b/lang/zh_CN.ts index 371eae03..f7c58d6d 100644 --- a/lang/zh_CN.ts +++ b/lang/zh_CN.ts @@ -318,6 +318,10 @@ room password error 房间密码错误 + + room is outdated + 房间已过时 + no such room 房间不存在 diff --git a/lua/client/i18n/zh_CN.lua b/lua/client/i18n/zh_CN.lua index b7083b45..c0315d17 100644 --- a/lua/client/i18n/zh_CN.lua +++ b/lua/client/i18n/zh_CN.lua @@ -495,6 +495,7 @@ Fk:loadTranslationTable{ ["#ChainStateChange"] = "%from %arg 了武将牌", ["#ChainDamage"] = "%from 处于连环状态,将受到传导的伤害", ["#ChangeKingdom"] = "%from 的国籍从 %arg 变成了 %arg2", + ["#RoomOutdated"] = "服务器更新完毕!该房间已过期,将无法再次游玩", } -- card footnote diff --git a/lua/server/request.lua b/lua/server/request.lua index 1b9ff419..66604a3b 100644 --- a/lua/server/request.lua +++ b/lua/server/request.lua @@ -181,7 +181,7 @@ request_handlers["newroom"] = function(s, id) s:registerRoom(id) end -request_handlers["reloadpackage"] = function(room, id, reqlist) +request_handlers["reloadpackage"] = function(_, _, reqlist) if not IsConsoleStart() then return end local path = reqlist[3] Fk:reloadPackage(path) diff --git a/lua/server/scheduler.lua b/lua/server/scheduler.lua index e1bf22d3..3df69ece 100644 --- a/lua/server/scheduler.lua +++ b/lua/server/scheduler.lua @@ -22,6 +22,8 @@ end) -- 仿照Room接口编写的request协程处理器 local requestRoom = setmetatable({ + id = -1, + runningRooms = runningRooms, -- minDelayTime 是当没有任何就绪房间时,可以睡眠的时间。 -- 因为这个时间是所有房间预期就绪用时的最小值,故称为minDelayTime。 @@ -130,6 +132,14 @@ local function mainLoop() -- 调用RoomThread的trySleep函数开始真正的睡眠。会被wakeUp(c++)唤醒。 requestRoom.thread:trySleep(time) + local runningRoomsCount = -1 -- 必有requestRoom,从-1开始算 + for _ in pairs(runningRooms) do + runningRoomsCount = runningRoomsCount + 1 + if runningRoomsCount > 0 then break end + end + if runningRoomsCount == 0 and requestRoom.thread:isOutdated() then + break + end -- verbose('[!] Waked up after %f ms...', (os.getms() - cur) / 1000) diff --git a/src/network/router.cpp b/src/network/router.cpp index 4de18c85..b0e6b412 100644 --- a/src/network/router.cpp +++ b/src/network/router.cpp @@ -153,107 +153,6 @@ void Router::abortRequest() { } void Router::handlePacket(const QByteArray &rawPacket) { -#ifndef FK_CLIENT_ONLY - static QMap lobby_actions; - if (lobby_actions.size() <= 0) { - lobby_actions["UpdateAvatar"] = [](ServerPlayer *sender, - const QString &jsonData) { - auto arr = String2Json(jsonData).array(); - auto avatar = arr[0].toString(); - - if (CheckSqlString(avatar)) { - auto sql = QString("UPDATE userinfo SET avatar='%1' WHERE id=%2;") - .arg(avatar) - .arg(sender->getId()); - ExecSQL(ServerInstance->getDatabase(), sql); - sender->setAvatar(avatar); - sender->doNotify("UpdateAvatar", avatar); - } - }; - lobby_actions["UpdatePassword"] = [](ServerPlayer *sender, - const QString &jsonData) { - auto arr = String2Json(jsonData).array(); - auto oldpw = arr[0].toString(); - auto newpw = arr[1].toString(); - auto sql_find = - QString("SELECT password, salt FROM userinfo WHERE id=%1;") - .arg(sender->getId()); - - auto passed = false; - auto arr2 = SelectFromDatabase(ServerInstance->getDatabase(), sql_find); - auto result = arr2[0].toObject(); - passed = (result["password"].toString() == - QCryptographicHash::hash( - oldpw.append(result["salt"].toString()).toLatin1(), - QCryptographicHash::Sha256) - .toHex()); - if (passed) { - auto sql_update = - QString("UPDATE userinfo SET password='%1' WHERE id=%2;") - .arg(QCryptographicHash::hash( - newpw.append(result["salt"].toString()).toLatin1(), - QCryptographicHash::Sha256) - .toHex()) - .arg(sender->getId()); - ExecSQL(ServerInstance->getDatabase(), sql_update); - } - - sender->doNotify("UpdatePassword", passed ? "1" : "0"); - }; - lobby_actions["CreateRoom"] = [](ServerPlayer *sender, - const QString &jsonData) { - auto arr = String2Json(jsonData).array(); - auto name = arr[0].toString(); - auto capacity = arr[1].toInt(); - auto timeout = arr[2].toInt(); - auto settings = - QJsonDocument(arr[3].toObject()).toJson(QJsonDocument::Compact); - ServerInstance->createRoom(sender, name, capacity, timeout, settings); - }; - lobby_actions["EnterRoom"] = [](ServerPlayer *sender, - const QString &jsonData) { - auto arr = String2Json(jsonData).array(); - auto roomId = arr[0].toInt(); - auto room = ServerInstance->findRoom(roomId); - if (room) { - auto settings = QJsonDocument::fromJson(room->getSettings()); - auto password = settings["password"].toString(); - if (password.isEmpty() || arr[1].toString() == password) { - room->addPlayer(sender); - } else { - sender->doNotify("ErrorMsg", "room password error"); - } - } else { - sender->doNotify("ErrorMsg", "no such room"); - } - }; - lobby_actions["ObserveRoom"] = [](ServerPlayer *sender, - const QString &jsonData) { - auto arr = String2Json(jsonData).array(); - auto roomId = arr[0].toInt(); - auto room = ServerInstance->findRoom(roomId); - if (room) { - auto settings = QJsonDocument::fromJson(room->getSettings()); - auto password = settings["password"].toString(); - if (password.isEmpty() || arr[1].toString() == password) { - room->addObserver(sender); - } else { - sender->doNotify("ErrorMsg", "room password error"); - } - } else { - sender->doNotify("ErrorMsg", "no such room"); - } - }; - lobby_actions["Chat"] = [](ServerPlayer *sender, const QString &jsonData) { - sender->getRoom()->chat(sender, jsonData); - }; - lobby_actions["RefreshRoomList"] = [](ServerPlayer *sender, - const QString &jsonData) { - ServerInstance->updateRoomList(sender); - }; - } -#endif - QJsonDocument packet = QJsonDocument::fromJson(rawPacket); if (packet.isNull() || !packet.isArray()) return; @@ -278,35 +177,7 @@ void Router::handlePacket(const QByteArray &rawPacket) { } Room *room = player->getRoom(); - if (room->isLobby() && lobby_actions.contains(command)) - lobby_actions[command](player, jsonData); - else { - if (command == "QuitRoom") { - room->removePlayer(player); - } else if (command == "AddRobot") { - if (ServerInstance->getConfig("enableBots").toBool()) room->addRobot(player); - } else if (command == "KickPlayer") { - int i = jsonData.toInt(); - auto p = room->findPlayer(i); - if (p && !room->isStarted()) { - room->removePlayer(p); - room->addRejectId(i); - QTimer::singleShot(30000, this, [=]() { - room->removeRejectId(i); - }); - } - } else if (command == "Ready") { - player->setReady(!player->isReady()); - room->doBroadcastNotify(room->getPlayers(), "ReadyChanged", - QString("[%1,%2]").arg(player->getId()).arg(player->isReady())); - } else if (command == "StartGame") { - room->manuallyStart(); - } else if (command == "Chat") { - room->chat(player, jsonData); - } else if (command == "PushRequest") { - room->pushRequest(QString("%1,").arg(player->getId()) + jsonData); - } - } + room->handlePacket(player, command, jsonData); } #endif } else if (type & TYPE_REQUEST) { diff --git a/src/server/room.cpp b/src/server/room.cpp index 1a811c14..9a27d8f3 100644 --- a/src/server/room.cpp +++ b/src/server/room.cpp @@ -22,7 +22,7 @@ Room::Room(RoomThread *m_thread) { id = server->nextRoomId; server->nextRoomId++; this->server = server; - this->m_thread = m_thread; + setThread(m_thread); if (m_thread) { // In case of lobby m_thread->addRoom(this); } @@ -60,7 +60,12 @@ Server *Room::getServer() const { return server; } RoomThread *Room::getThread() const { return m_thread; } -void Room::setThread(RoomThread *t) { m_thread = t; } +void Room::setThread(RoomThread *t) { + m_thread = t; + if (t != nullptr) { + md5 = t->getMd5(); + } +} int Room::getId() const { return id; } @@ -366,6 +371,12 @@ int Room::getTimeout() const { return timeout; } void Room::setTimeout(int timeout) { this->timeout = timeout; } +bool Room::isOutdated() { + bool ret = md5 != server->getMd5(); + if (ret) md5 = ""; + return ret; +} + bool Room::isStarted() const { return gameStarted; } void Room::doBroadcastNotify(const QList targets, @@ -616,3 +627,186 @@ void Room::addRejectId(int id) { void Room::removeRejectId(int id) { rejected_players.removeOne(id); } + +// ------------------------------------------------ +static void updateAvatar(ServerPlayer *sender, const QString &jsonData) { + auto arr = String2Json(jsonData).array(); + auto avatar = arr[0].toString(); + + if (CheckSqlString(avatar)) { + auto sql = QString("UPDATE userinfo SET avatar='%1' WHERE id=%2;") + .arg(avatar) + .arg(sender->getId()); + ExecSQL(ServerInstance->getDatabase(), sql); + sender->setAvatar(avatar); + sender->doNotify("UpdateAvatar", avatar); + } +} + +static void updatePassword(ServerPlayer *sender, const QString &jsonData) { + auto arr = String2Json(jsonData).array(); + auto oldpw = arr[0].toString(); + auto newpw = arr[1].toString(); + auto sql_find = + QString("SELECT password, salt FROM userinfo WHERE id=%1;") + .arg(sender->getId()); + + auto passed = false; + auto arr2 = SelectFromDatabase(ServerInstance->getDatabase(), sql_find); + auto result = arr2[0].toObject(); + passed = (result["password"].toString() == + QCryptographicHash::hash( + oldpw.append(result["salt"].toString()).toLatin1(), + QCryptographicHash::Sha256) + .toHex()); + if (passed) { + auto sql_update = + QString("UPDATE userinfo SET password='%1' WHERE id=%2;") + .arg(QCryptographicHash::hash( + newpw.append(result["salt"].toString()).toLatin1(), + QCryptographicHash::Sha256) + .toHex()) + .arg(sender->getId()); + ExecSQL(ServerInstance->getDatabase(), sql_update); + } + + sender->doNotify("UpdatePassword", passed ? "1" : "0"); +} + +static void createRoom(ServerPlayer *sender, const QString &jsonData) { + auto arr = String2Json(jsonData).array(); + auto name = arr[0].toString(); + auto capacity = arr[1].toInt(); + auto timeout = arr[2].toInt(); + auto settings = + QJsonDocument(arr[3].toObject()).toJson(QJsonDocument::Compact); + ServerInstance->createRoom(sender, name, capacity, timeout, settings); +} + +static void enterRoom(ServerPlayer *sender, const QString &jsonData) { + auto arr = String2Json(jsonData).array(); + auto roomId = arr[0].toInt(); + auto room = ServerInstance->findRoom(roomId); + if (room) { + auto settings = QJsonDocument::fromJson(room->getSettings()); + auto password = settings["password"].toString(); + if (password.isEmpty() || arr[1].toString() == password) { + if (room->isOutdated()) { + sender->doNotify("ErrorMsg", "room is outdated"); + } else { + room->addPlayer(sender); + } + } else { + sender->doNotify("ErrorMsg", "room password error"); + } + } else { + sender->doNotify("ErrorMsg", "no such room"); + } +} + +static void observeRoom(ServerPlayer *sender, const QString &jsonData) { + auto arr = String2Json(jsonData).array(); + auto roomId = arr[0].toInt(); + auto room = ServerInstance->findRoom(roomId); + if (room) { + auto settings = QJsonDocument::fromJson(room->getSettings()); + auto password = settings["password"].toString(); + if (password.isEmpty() || arr[1].toString() == password) { + if (room->isOutdated()) { + sender->doNotify("ErrorMsg", "room is outdated"); + } else { + room->addObserver(sender); + } + } else { + sender->doNotify("ErrorMsg", "room password error"); + } + } else { + sender->doNotify("ErrorMsg", "no such room"); + } +} + +static void refreshRoomList(ServerPlayer *sender, const QString &) { + ServerInstance->updateRoomList(sender); +}; + +static void quitRoom(ServerPlayer *player, const QString &) { + auto room = player->getRoom(); + room->removePlayer(player); + if (room->isOutdated()) { + player->kicked(); + } +} + +static void addRobot(ServerPlayer *player, const QString &) { + auto room = player->getRoom(); + if (ServerInstance->getConfig("enableBots").toBool()) + room->addRobot(player); +} + +static void kickPlayer(ServerPlayer *player, const QString &jsonData) { + auto room = player->getRoom(); + int i = jsonData.toInt(); + auto p = room->findPlayer(i); + if (p && !room->isStarted()) { + room->removePlayer(p); + room->addRejectId(i); + QTimer::singleShot(30000, room, [=]() { + room->removeRejectId(i); + }); + } +} + +static void ready(ServerPlayer *player, const QString &) { + auto room = player->getRoom(); + player->setReady(!player->isReady()); + room->doBroadcastNotify(room->getPlayers(), "ReadyChanged", + QString("[%1,%2]").arg(player->getId()).arg(player->isReady())); +} + +static void startGame(ServerPlayer *player, const QString &) { + auto room = player->getRoom(); + if (room->isOutdated()) { + foreach (auto p, room->getPlayers()) { + p->doNotify("ErrorMsg", "room is outdated"); + p->kicked(); + } + } else { + room->manuallyStart(); + } +} + +typedef void (*room_cb)(ServerPlayer *, const QString &); +static const QMap lobby_actions = { + {"UpdateAvatar", updateAvatar}, + {"UpdatePassword", updatePassword}, + {"CreateRoom", createRoom}, + {"EnterRoom", enterRoom}, + {"ObserveRoom", observeRoom}, + {"RefreshRoomList", refreshRoomList}, +}; + +static const QMap room_actions = { + {"QuitRoom", quitRoom}, + {"AddRobot", addRobot}, + {"KickPlayer", kickPlayer}, + {"Ready", ready}, + {"StartGame", startGame}, +}; + +void Room::handlePacket(ServerPlayer *sender, const QString &command, + const QString &jsonData) { + if (command == "Chat") { + chat(sender, jsonData); + return; + } else if (command == "PushRequest") { + if (!isLobby()) + pushRequest(QString("%1,").arg(sender->getId()) + jsonData); + } + + auto func_table = lobby_actions; + if (!isLobby()) func_table = room_actions; + auto func = func_table[command]; + if (func) { + func(sender, jsonData); + } +} diff --git a/src/server/room.h b/src/server/room.h index 2cf9a13a..221be5b8 100644 --- a/src/server/room.h +++ b/src/server/room.h @@ -50,6 +50,8 @@ class Room : public QObject { int getTimeout() const; void setTimeout(int timeout); + bool isOutdated(); + bool isStarted() const; // ====================================} @@ -65,6 +67,10 @@ class Room : public QObject { void addRejectId(int id); void removeRejectId(int id); + + // router用 + void handlePacket(ServerPlayer *sender, const QString &command, + const QString &jsonData); signals: void abandoned(); @@ -90,6 +96,7 @@ class Room : public QObject { bool m_ready; int timeout; + QString md5; void addRunRate(int id, const QString &mode); void updatePlayerGameData(int id, const QString &mode); diff --git a/src/server/roomthread.cpp b/src/server/roomthread.cpp index 104d592c..91206caf 100644 --- a/src/server/roomthread.cpp +++ b/src/server/roomthread.cpp @@ -3,6 +3,7 @@ #include "roomthread.h" #include "server.h" #include "util.h" +#include #ifndef FK_SERVER_ONLY #include "client.h" @@ -13,6 +14,7 @@ RoomThread::RoomThread(Server *m_server) { this->m_server = m_server; m_capacity = 100; // TODO: server cfg terminated = false; + md5 = m_server->getMd5(); L = CreateLuaState(); DoLuaScript(L, "lua/freekill.lua"); @@ -26,6 +28,7 @@ RoomThread::~RoomThread() { wait(); } lua_close(L); + m_server->removeThread(this); // foreach (auto room, room_list) { // room->deleteLater(); // } @@ -40,6 +43,8 @@ bool RoomThread::isFull() const { return m_capacity <= 0; } +QString RoomThread::getMd5() const { return md5; } + Room *RoomThread::getRoom(int id) const { return m_server->findRoom(id); } @@ -52,6 +57,10 @@ void RoomThread::addRoom(Room *room) { void RoomThread::removeRoom(Room *room) { room->setThread(nullptr); m_capacity++; + if (m_capacity == 100 // TODO: server cfg + && isOutdated()) { + deleteLater(); + } } QString RoomThread::fetchRequest() { @@ -118,3 +127,13 @@ bool RoomThread::isConsoleStart() const { return false; #endif } + +bool RoomThread::isOutdated() { + bool ret = md5 != m_server->getMd5(); + if (ret) { + // 让以后每次都outdate + // 不然反复disable/enable的情况下会出乱子 + md5 = ""; + } + return ret; +} diff --git a/src/server/roomthread.h b/src/server/roomthread.h index 15cd1964..25d0afe3 100644 --- a/src/server/roomthread.h +++ b/src/server/roomthread.h @@ -16,6 +16,7 @@ class RoomThread : public QThread { Server *getServer() const; bool isFull() const; + QString getMd5() const; Room *getRoom(int id) const; void addRoom(Room *room); void removeRoom(Room *room); @@ -32,6 +33,9 @@ class RoomThread : public QThread { bool isTerminated() const; bool isConsoleStart() const; + + bool isOutdated(); + protected: virtual void run(); @@ -39,6 +43,7 @@ class RoomThread : public QThread { Server *m_server; // QList room_list; int m_capacity; + QString md5; lua_State *L; QMutex request_queue_mutex; diff --git a/src/server/server.cpp b/src/server/server.cpp index 9a62d90e..996157b1 100644 --- a/src/server/server.cpp +++ b/src/server/server.cpp @@ -112,14 +112,14 @@ void Server::createRoom(ServerPlayer *owner, const QString &name, int capacity, RoomThread *thread = nullptr; foreach (auto t, threads) { - if (!t->isFull()) { + if (!t->isFull() && !t->isOutdated()) { thread = t; break; } } + if (!thread && nextRoomId != 0) { - thread = new RoomThread(this); - threads.append(thread); + thread = createThread(); } if (!idle_rooms.isEmpty()) { @@ -128,6 +128,7 @@ void Server::createRoom(ServerPlayer *owner, const QString &name, int capacity, nextRoomId++; room->setAbandoned(false); room->setThread(thread); + thread->addRoom(room); rooms.insert(room->getId(), room); } else { room = new Room(thread); @@ -151,6 +152,16 @@ Room *Server::findRoom(int id) const { return rooms.value(id); } Room *Server::lobby() const { return m_lobby; } +RoomThread *Server::createThread() { + RoomThread *thread = new RoomThread(this); + threads.append(thread); + return thread; +} + +void Server::removeThread(RoomThread *thread) { + threads.removeOne(thread); +} + ServerPlayer *Server::findPlayer(int id) const { return players.value(id); } void Server::addPlayer(ServerPlayer *player) { @@ -183,6 +194,7 @@ void Server::updateRoomList(ServerPlayer *teller) { obj << count; obj << cap; obj << !password.isEmpty(); + obj << room->isOutdated(); if (count == cap) arr << obj; @@ -670,6 +682,30 @@ void Server::endTransaction() { transaction_mutex.unlock(); } +const QString &Server::getMd5() const { + return md5; +} + +void Server::refreshMd5() { + md5 = calcFileMD5(); + foreach (auto room, rooms) { + if (room->isOutdated()) { + if (!room->isStarted()) { + foreach (auto p, room->getPlayers()) { + p->doNotify("ErrorMsg", "room is outdated"); + p->kicked(); + } + } else { + room->doBroadcastNotify(room->getPlayers(), "GameLog", + "{\"type\":\"#RoomOutdated\",\"toast\":true}"); + } + } + } + foreach (auto p, lobby()->getPlayers()) { + emit p->kicked(); + } +} + void Server::readPendingDatagrams() { while (udpSocket->hasPendingDatagrams()) { QNetworkDatagram datagram = udpSocket->receiveDatagram(); diff --git a/src/server/server.h b/src/server/server.h index 61b02088..f2baaa53 100644 --- a/src/server/server.h +++ b/src/server/server.h @@ -31,6 +31,9 @@ public: Room *findRoom(int id) const; Room *lobby() const; + RoomThread *createThread(); + void removeThread(RoomThread *thread); + ServerPlayer *findPlayer(int id) const; void addPlayer(ServerPlayer *player); void removePlayer(int id); @@ -50,6 +53,9 @@ public: void beginTransaction(); void endTransaction(); + const QString &getMd5() const; + void refreshMd5(); + signals: void roomCreated(Room *room); void playerAdded(ServerPlayer *player); diff --git a/src/server/shell.cpp b/src/server/shell.cpp index 9b2ee0ca..c286701d 100644 --- a/src/server/shell.cpp +++ b/src/server/shell.cpp @@ -117,11 +117,13 @@ void Shell::upgradeCommand(QStringList &list) { auto obj = a.toObject(); Pacman->upgradePack(obj["name"].toString()); } + ServerInstance->refreshMd5(); return; } auto pack = list[0]; Pacman->upgradePack(pack); + ServerInstance->refreshMd5(); } void Shell::enableCommand(QStringList &list) { @@ -132,6 +134,7 @@ void Shell::enableCommand(QStringList &list) { auto pack = list[0]; Pacman->enablePack(pack); + ServerInstance->refreshMd5(); } void Shell::disableCommand(QStringList &list) { @@ -142,6 +145,7 @@ void Shell::disableCommand(QStringList &list) { auto pack = list[0]; Pacman->disablePack(pack); + ServerInstance->refreshMd5(); } void Shell::lspkgCommand(QStringList &) { @@ -380,33 +384,32 @@ Shell::Shell() { setObjectName("Shell"); signal(SIGINT, sigintHandler); - static QHash handlers; - if (handlers.size() == 0) { - handlers["help"] = &Shell::helpCommand; - handlers["?"] = &Shell::helpCommand; - handlers["lsplayer"] = &Shell::lspCommand; - handlers["lsroom"] = &Shell::lsrCommand; - handlers["install"] = &Shell::installCommand; - handlers["remove"] = &Shell::removeCommand; - handlers["upgrade"] = &Shell::upgradeCommand; - handlers["u"] = &Shell::upgradeCommand; - handlers["lspkg"] = &Shell::lspkgCommand; - handlers["enable"] = &Shell::enableCommand; - handlers["disable"] = &Shell::disableCommand; - handlers["kick"] = &Shell::kickCommand; - handlers["msg"] = &Shell::msgCommand; - handlers["m"] = &Shell::msgCommand; - handlers["ban"] = &Shell::banCommand; - handlers["unban"] = &Shell::unbanCommand; - handlers["banip"] = &Shell::banipCommand; - handlers["unbanip"] = &Shell::unbanipCommand; - handlers["banuuid"] = &Shell::banUuidCommand; - handlers["unbanuuid"] = &Shell::unbanUuidCommand; - handlers["reloadconf"] = &Shell::reloadConfCommand; - handlers["r"] = &Shell::reloadConfCommand; - handlers["resetpassword"] = &Shell::resetPasswordCommand; - handlers["rp"] = &Shell::resetPasswordCommand; - } + static const QHash handlers = { + {"help", &Shell::helpCommand}, + {"?", &Shell::helpCommand}, + {"lsplayer", &Shell::lspCommand}, + {"lsroom", &Shell::lsrCommand}, + {"install", &Shell::installCommand}, + {"remove", &Shell::removeCommand}, + {"upgrade", &Shell::upgradeCommand}, + {"u", &Shell::upgradeCommand}, + {"lspkg", &Shell::lspkgCommand}, + {"enable", &Shell::enableCommand}, + {"disable", &Shell::disableCommand}, + {"kick", &Shell::kickCommand}, + {"msg", &Shell::msgCommand}, + {"m", &Shell::msgCommand}, + {"ban", &Shell::banCommand}, + {"unban", &Shell::unbanCommand}, + {"banip", &Shell::banipCommand}, + {"unbanip", &Shell::unbanipCommand}, + {"banuuid", &Shell::banUuidCommand}, + {"unbanuuid", &Shell::unbanUuidCommand}, + {"reloadconf", &Shell::reloadConfCommand}, + {"r", &Shell::reloadConfCommand}, + {"resetpassword", &Shell::resetPasswordCommand}, + {"rp", &Shell::resetPasswordCommand}, + }; handler_map = handlers; } diff --git a/src/swig/server.i b/src/swig/server.i index 82908a2b..ba72a769 100644 --- a/src/swig/server.i +++ b/src/swig/server.i @@ -41,6 +41,7 @@ public: bool isTerminated() const; bool isConsoleStart() const; + bool isOutdated(); }; %{