diff --git a/Fk/Pages/Replay.qml b/Fk/Pages/Replay.qml
index 6f2742bf..c9e86ce5 100644
--- a/Fk/Pages/Replay.qml
+++ b/Fk/Pages/Replay.qml
@@ -3,6 +3,7 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
+import QtQuick.Dialogs
import Fk
Item {
@@ -29,6 +30,12 @@ Item {
Menu {
id: menu
y: bar.height
+ MenuItem {
+ text: qsTr("Replay from file")
+ onTriggered: {
+ fdialog.open();
+ }
+ }
}
}
}
@@ -104,7 +111,7 @@ Item {
onClicked: {
config.observing = true;
config.replaying = true;
- Backend.playRecord(fileName);
+ Backend.playRecord("recording/" + fileName);
}
}
@@ -122,6 +129,17 @@ Item {
}
}
+ FileDialog {
+ id: fdialog
+ nameFilters: ["FK Rep Files (*.fk.rep)"];
+ onAccepted: {
+ config.observing = true;
+ config.replaying = true;
+ let str = selectedFile.toString(); // QUrl -> string
+ Backend.playRecord(str);
+ }
+ }
+
function updateList() {
model.clear();
const data = Backend.ls("recording");
diff --git a/Fk/Pages/Room.qml b/Fk/Pages/Room.qml
index 7e6d5993..c1eae3ea 100644
--- a/Fk/Pages/Room.qml
+++ b/Fk/Pages/Room.qml
@@ -210,22 +210,55 @@ Item {
}
}
Rectangle {
- x: parent.width / 2 + 80
- y: parent.height / 2
+ x: parent.width / 2 + 60
+ y: parent.height / 2 - 30
color: "snow"
opacity: 0.8
radius: 6
- height: childrenRect.height + 16
- width: childrenRect.width + 16
visible: !isStarted
+ width: 280
+ height: 280
- Text {
- x: 8; y: 8
- Component.onCompleted: {
- const data = JSON.parse(Backend.callLuaFunction("GetRoomConfig", []));
- text = Backend.translate("LuckCardNum") + data.luckTime + "
" + Backend.translate("ResponseTime") + config.roomTimeout
- + "
" + Backend.translate("GeneralBoxNum") + data.generalNum + (data.enableFreeAssign ? "
" + Backend.translate("IncludeFreeAssign") : "")
- + (data.enableDeputy ? "
" + Backend.translate("IncludeDeputy") : "")
+ Flickable {
+ id: flickableContainer
+ ScrollBar.vertical: ScrollBar {}
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.top: parent.top
+ anchors.topMargin: 10
+ flickableDirection: Flickable.VerticalFlick
+ width: parent.width - 10
+ height: parent.height - 10
+ contentHeight: roominfo.height
+ clip: true
+
+ Text {
+ id: roominfo
+ font.pixelSize: 16
+ width: parent.width
+ wrapMode: TextEdit.WordWrap
+ Component.onCompleted: {
+ const data = JSON.parse(Backend.callLuaFunction("GetRoomConfig", []));
+ let cardpack = JSON.parse(Backend.callLuaFunction("GetAllCardPack", []));
+ cardpack = cardpack.filter(p => !data.disabledPack.includes(p));
+
+ text = "游戏模式:" + Backend.translate(data.gameMode) + "
"
+ + Backend.translate("LuckCardNum") + "" + data.luckTime + "
"
+ + Backend.translate("ResponseTime") + "" + config.roomTimeout + "
"
+ + Backend.translate("GeneralBoxNum") + "" + data.generalNum + ""
+ + (data.enableFreeAssign ? "
" + Backend.translate("IncludeFreeAssign") : "")
+ + (data.enableDeputy ? " " + Backend.translate("IncludeDeputy") : "")
+ + '
使用牌堆:' + cardpack.map(e => {
+ let ret = Backend.translate(e);
+ if (ret.search(/特殊牌|衍生牌/) === -1) { // TODO: 这种东西最好还是变量名规范化= =
+ ret = "" + ret + "";
+ } else {
+ ret = '' + ret + "";
+ }
+ return ret;
+ }).join(',')
+ //+ '
禁包:' + data.disabledPack.map(e => Backend.translate(e)).join(',')
+ //+ '
禁将:' + data.disabledGenerals.map(e => Backend.translate(e)).join(',')
+ }
}
}
}
diff --git a/Fk/PhotoElement/LimitSkillArea.qml b/Fk/PhotoElement/LimitSkillArea.qml
index 4632fbdf..00061eff 100644
--- a/Fk/PhotoElement/LimitSkillArea.qml
+++ b/Fk/PhotoElement/LimitSkillArea.qml
@@ -22,6 +22,9 @@ ColumnLayout {
const data = skills.get(i);
if (data.skillname_ === skill) {
data.times = times;
+ if (times == -1) {
+ skills.remove(i);
+ }
return;
}
}
diff --git a/Fk/PhotoElement/RoleComboBox.qml b/Fk/PhotoElement/RoleComboBox.qml
index 2b326f00..d146461e 100644
--- a/Fk/PhotoElement/RoleComboBox.qml
+++ b/Fk/PhotoElement/RoleComboBox.qml
@@ -8,7 +8,7 @@ Image {
property var options: ["unknown", "loyalist", "rebel", "renegade"]
id: root
- source: visible ? SkinBank.ROLE_DIR + value : ""
+ source: visible ? SkinBank.getRolePic(value) : ""
visible: value != "hidden"
Image {
diff --git a/Fk/skin-bank.js b/Fk/skin-bank.js
index d45e2fc4..ab56bc06 100644
--- a/Fk/skin-bank.js
+++ b/Fk/skin-bank.js
@@ -55,6 +55,7 @@ function getCardPicture(cidOrName) {
return path;
} else {
for (let dir of Backend.ls(AppPath + "/packages/")) {
+ if (dir.endsWith(".disabled")) continue;
path = AppPath + "/packages/" + dir + "/image/card/" + name + ".png";
if (Backend.exists(path)) return path;
}
@@ -70,6 +71,7 @@ function getDelayedTrickPicture(name) {
return path;
} else {
for (let dir of Backend.ls(AppPath + "/packages/")) {
+ if (dir.endsWith(".disabled")) continue;
path = AppPath + "/packages/" + dir + "/image/card/delayedTrick/" + name + ".png";
if (Backend.exists(path)) return path;
}
@@ -87,6 +89,7 @@ function getEquipIcon(cid, icon) {
return path;
} else {
for (let dir of Backend.ls(AppPath + "/packages/")) {
+ if (dir.endsWith(".disabled")) continue;
path = AppPath + "/packages/" + dir + "/image/card/equipIcon/" + name + ".png";
if (Backend.exists(path)) return path;
}
@@ -98,6 +101,7 @@ function getPhotoBack(kingdom) {
let path = PHOTO_BACK_DIR + kingdom + ".png";
if (!Backend.exists(path)) {
for (let dir of Backend.ls(AppPath + "/packages/")) {
+ if (dir.endsWith(".disabled")) continue;
path = AppPath + "/packages/" + dir + "/image/kingdom/" + kingdom + "-back.png";
if (Backend.exists(path)) return path;
}
@@ -111,6 +115,7 @@ function getGeneralCardDir(kingdom) {
let path = GENERALCARD_DIR + kingdom + ".png";
if (!Backend.exists(path)) {
for (let dir of Backend.ls(AppPath + "/packages/")) {
+ if (dir.endsWith(".disabled")) continue;
path = AppPath + "/packages/" + dir + "/image/kingdom/" + kingdom + "-back.png";
if (Backend.exists(path))
return AppPath + "/packages/" + dir + "/image/kingdom/";
@@ -119,3 +124,17 @@ function getGeneralCardDir(kingdom) {
return GENERALCARD_DIR;
}
}
+
+function getRolePic(role) {
+ let path = ROLE_DIR + role + ".png";
+ if (Backend.exists(path)) {
+ return path;
+ } else {
+ for (let dir of Backend.ls(AppPath + "/packages/")) {
+ if (dir.endsWith(".disabled")) continue;
+ path = AppPath + "/packages/" + dir + "/image/role/" + name + ".png";
+ if (Backend.exists(path)) return path;
+ }
+ }
+ return ROLE_DIR + "unknown.png";
+}
diff --git a/lua/client/client.lua b/lua/client/client.lua
index 2cdf5844..f79424ab 100644
--- a/lua/client/client.lua
+++ b/lua/client/client.lua
@@ -585,21 +585,6 @@ fk.client_callback["ShowCard"] = function(jsonData)
})
end
-fk.client_callback["LoseSkill"] = function(jsonData)
- -- jsonData: [ int player_id, string skill_name ]
- local data = json.decode(jsonData)
- local id, skill_name, prelight = data[1], data[2], data[3]
- local target = ClientInstance:getPlayerById(id)
- local skill = Fk.skills[skill_name]
- if not prelight then
- target:loseSkill(skill)
- end
-
- if skill.visible then
- ClientInstance:notifyUI("LoseSkill", jsonData)
- end
-end
-
-- 说是限定技,其实也适用于觉醒技、转换技、使命技
---@param skill Skill
---@param times integer
@@ -613,15 +598,99 @@ local function updateLimitSkill(pid, skill, times)
end
end
+fk.client_callback["LoseSkill"] = function(jsonData)
+ -- jsonData: [ int player_id, string skill_name ]
+ local data = json.decode(jsonData)
+ local id, skill_name, fake = data[1], data[2], data[3]
+ local target = ClientInstance:getPlayerById(id)
+ local skill = Fk.skills[skill_name]
+
+ if not fake then
+ target:loseSkill(skill)
+ if skill.visible then
+ ClientInstance:notifyUI("LoseSkill", jsonData)
+ end
+ elseif skill.visible then
+ -- 按理说能弄得更好的但还是复制粘贴舒服
+ local sks = { table.unpack(skill.related_skills) }
+ --[[ 需要大伙都适配好main_skill或者讨论出更好方案才行。不敢轻举妄动
+ local sks = table.filter(skill.related_skills, function(s)
+ return s.main_skill == skill
+ end)
+ --]]
+ table.insert(sks, skill)
+ table.removeOne(target.player_skills, skill)
+ local chk = false
+
+ if table.find(sks, function(s) return s:isInstanceOf(TriggerSkill) end) then
+ chk = true
+ ClientInstance:notifyUI("LoseSkill", jsonData)
+ end
+
+ local active = table.filter(sks, function(s)
+ return s:isInstanceOf(ActiveSkill) or s:isInstanceOf(ViewAsSkill)
+ end)
+
+ if #active > 0 then
+ chk = true
+ ClientInstance:notifyUI("LoseSkill", json.encode {
+ id, skill_name,
+ })
+ end
+
+ if not chk then
+ ClientInstance:notifyUI("LoseSkill", json.encode {
+ id, skill_name,
+ })
+ end
+ end
+
+ updateLimitSkill(id, skill, -1)
+end
+
fk.client_callback["AddSkill"] = function(jsonData)
-- jsonData: [ int player_id, string skill_name ]
local data = json.decode(jsonData)
- local id, skill_name = data[1], data[2]
+ local id, skill_name, fake = data[1], data[2], data[3]
local target = ClientInstance:getPlayerById(id)
local skill = Fk.skills[skill_name]
- target:addSkill(skill)
- if skill.visible then
- ClientInstance:notifyUI("AddSkill", jsonData)
+
+ if not fake then
+ target:addSkill(skill)
+ if skill.visible then
+ ClientInstance:notifyUI("AddSkill", jsonData)
+ end
+ elseif skill.visible then
+ -- 添加假技能:服务器只会传一个主技能来。
+ -- 若有主动技则添加按钮,若有触发技则添加预亮按钮。
+ -- 无视状态技。
+ local sks = { table.unpack(skill.related_skills) }
+ table.insert(sks, skill)
+ table.insert(target.player_skills, skill)
+ local chk = false
+
+ if table.find(sks, function(s) return s:isInstanceOf(TriggerSkill) end) then
+ chk = true
+ ClientInstance:notifyUI("AddSkill", jsonData)
+ end
+
+ local active = table.filter(sks, function(s)
+ return s:isInstanceOf(ActiveSkill) or s:isInstanceOf(ViewAsSkill)
+ end)
+
+ if #active > 0 then
+ chk = true
+ ClientInstance:notifyUI("AddSkill", json.encode {
+ id, skill_name,
+ })
+ end
+
+ -- 面板上总得有点啥东西表明自己有技能吧 = =
+ if not chk then
+ ClientInstance:notifyUI("AddSkill", json.encode {
+ id, skill_name,
+ })
+ end
end
if skill.frequency == Skill.Quest then
diff --git a/lua/core/player.lua b/lua/core/player.lua
index 61257d1a..224aa4aa 100644
--- a/lua/core/player.lua
+++ b/lua/core/player.lua
@@ -678,6 +678,13 @@ function Player:hasSkill(skill, ignoreNullified, ignoreAlive)
return true
end
+ if self:isInstanceOf(ServerPlayer) and -- isInstanceOf(nil) will return false
+ table.contains(self._fake_skills, skill) and
+ table.contains(self.prelighted_skills, skill) then
+
+ return true
+ end
+
for _, v in pairs(self.derivative_skills) do
if table.contains(v, skill) then
return true
diff --git a/lua/core/skill_type/trigger.lua b/lua/core/skill_type/trigger.lua
index 799c6ecc..d1c5b538 100644
--- a/lua/core/skill_type/trigger.lua
+++ b/lua/core/skill_type/trigger.lua
@@ -56,8 +56,15 @@ end
-- do cost and skill effect.
-- DO NOT modify this function
function TriggerSkill:doCost(event, target, player, data)
+ local start_time = os.getms()
local ret = self:cost(event, target, player, data)
+ local end_time = os.getms()
+
local room = player.room
+ -- 对于那种cost直接返回true的锁定技,如果是预亮技,那么还是询问一下好
+ if ret and player:isFakeSkill(self) and end_time - start_time < 10000 then
+ ret = room:askForSkillInvoke(player, self.name)
+ end
local cost_data_bak = self.cost_data
room.logic:trigger(fk.BeforeTriggerSkillUse, player, { skill = self, willUse = ret })
diff --git a/lua/core/skill_type/usable_skill.lua b/lua/core/skill_type/usable_skill.lua
index 7612d947..4b1368fd 100644
--- a/lua/core/skill_type/usable_skill.lua
+++ b/lua/core/skill_type/usable_skill.lua
@@ -1,6 +1,7 @@
-- SPDX-License-Identifier: GPL-3.0-or-later
---@class UsableSkill : Skill
+---@field public main_skill UsableSkill
---@field public max_use_time integer[]
---@field public expand_pile string
local UsableSkill = Skill:subclass("UsableSkill")
diff --git a/lua/fk_ex.lua b/lua/fk_ex.lua
index 935f4e47..8be1277a 100644
--- a/lua/fk_ex.lua
+++ b/lua/fk_ex.lua
@@ -42,6 +42,8 @@ end
local function readUsableSpecToSkill(skill, spec)
readCommonSpecToSkill(skill, spec)
+ assert(spec.main_skill == nil or spec.main_skill:isInstanceOf(UsableSkill))
+ skill.main_skill = spec.main_skill
skill.target_num = spec.target_num or skill.target_num
skill.min_target_num = spec.min_target_num or skill.min_target_num
skill.max_target_num = spec.max_target_num or skill.max_target_num
diff --git a/lua/server/events/skill.lua b/lua/server/events/skill.lua
index ff391338..1d3c304d 100644
--- a/lua/server/events/skill.lua
+++ b/lua/server/events/skill.lua
@@ -1,9 +1,14 @@
-- SPDX-License-Identifier: GPL-3.0-or-later
GameEvent.functions[GameEvent.SkillEffect] = function(self)
- local effect_cb, player, skill = table.unpack(self.data)
+ local effect_cb, player, _skill = table.unpack(self.data)
local room = self.room
local logic = room.logic
+ local skill = _skill.main_skill and _skill.main_skill or _skill
+
+ if player then
+ player:addSkillUseHistory(skill.name)
+ end
local cost_data_bak = skill.cost_data
logic:trigger(fk.SkillEffect, player, skill)
diff --git a/lua/server/room.lua b/lua/server/room.lua
index 4bbeb212..2ad3f903 100644
--- a/lua/server/room.lua
+++ b/lua/server/room.lua
@@ -829,6 +829,15 @@ function Room:notifyMoveFocus(players, command)
table.insert(ids, p.id)
end
+ local tempSk = Fk.skills[command]
+ if tempSk and #players == 1 then
+ local p = players[1]
+ if p:isFakeSkill(tempSk) then
+ command = ""
+ ids = table.map(self.alive_players, Util.IdMapper)
+ end
+ end
+
self:doBroadcastNotify("MoveFocus", json.encode{
ids,
command
@@ -2987,7 +2996,6 @@ function Room:useSkill(player, skill, effect_cb)
player:getSwitchSkillState(switchSkillName, true)
)
end
- player:addSkillUseHistory(skill.name)
if effect_cb then
return execGameEvent(GameEvent.SkillEffect, effect_cb, player, skill)
diff --git a/lua/server/serverplayer.lua b/lua/server/serverplayer.lua
index ac8dc28d..35ee989f 100644
--- a/lua/server/serverplayer.lua
+++ b/lua/server/serverplayer.lua
@@ -14,6 +14,8 @@
---@field public phase_state table[]
---@field public phase_index integer
---@field public role_shown boolean
+---@field private _fake_skills Skill[]
+---@field public prelighted_skills Skill[]
---@field private _timewaste_count integer
---@field public ai AI
---@field public ai_data any
@@ -35,6 +37,11 @@ function ServerPlayer:initialize(_self)
self.reply_cancel = false
self.phases = {}
self.skipped_phases = {}
+
+ self._fake_skills = {}
+ self.prelighted_skills = {}
+ self._prelighted_skills = {}
+
self._timewaste_count = 0
self.ai = RandomAI:new(self)
end
@@ -702,13 +709,70 @@ end
-- Hegemony func
+---@param skill Skill
+function ServerPlayer:addFakeSkill(skill)
+ assert(skill:isInstanceOf(Skill))
+ if table.contains(self._fake_skills, skill) then return end
+
+ table.insert(self._fake_skills, skill)
+ for _, s in ipairs(skill.related_skills) do
+ -- if s.main_skill == skill then -- TODO: need more detailed
+ table.insert(self._fake_skills, s)
+ -- end
+ end
+
+ -- TODO
+ self:doNotify("AddSkill", json.encode{ self.id, skill.name, true })
+end
+
+---@param skill Skill
+function ServerPlayer:loseFakeSkill(skill)
+ assert(skill:isInstanceOf(Skill))
+ if not table.contains(self._fake_skills, skill) then return end
+
+ table.removeOne(self._fake_skills, skill)
+ for _, s in ipairs(skill.related_skills) do
+ table.removeOne(self._fake_skills, s)
+ end
+
+ -- TODO
+ self:doNotify("LoseSkill", json.encode{ self.id, skill.name, true })
+end
+
+function ServerPlayer:isFakeSkill(skill)
+ if type(skill) == "string" then skill = Fk.skills[skill] end
+ assert(skill:isInstanceOf(Skill))
+ return table.contains(self._fake_skills, skill)
+end
+
+---@param skill string | Skill
+---@param isPrelight boolean | nil
function ServerPlayer:prelightSkill(skill, isPrelight)
- if isPrelight then
+ if type(skill) == "string" then skill = Fk.skills[skill] end
+ assert(skill:isInstanceOf(Skill))
+
+ if not self._prelighted_skills[skill] and not self:hasSkill(skill) then
+ self._prelighted_skills[skill] = true
+ -- to attach skill to room
self:addSkill(skill)
- else
self:loseSkill(skill)
end
- self:doNotify("PrelightSkill", json.encode{ skill, isPrelight })
+
+ if isPrelight then
+ -- self:addSkill(skill)
+ table.insert(self.prelighted_skills, skill)
+ for _, s in ipairs(skill.related_skills) do
+ table.insert(self.prelighted_skills, s)
+ end
+ else
+ -- self:loseSkill(skill)
+ table.removeOne(self.prelighted_skills, skill)
+ for _, s in ipairs(skill.related_skills) do
+ table.removeOne(self.prelighted_skills, s)
+ end
+ end
+
+ self:doNotify("PrelightSkill", json.encode{ skill.name, isPrelight })
end
function ServerPlayer:revealGeneral(isDeputy)
@@ -725,10 +789,7 @@ function ServerPlayer:revealGeneral(isDeputy)
local general = Fk.generals[generalName]
for _, s in ipairs(general:getSkillNameList()) do
local skill = Fk.skills[s]
- if skill:isInstanceOf(TriggerSkill) or table.find(skill.related_skills,
- function(s) return s:isInstanceOf(TriggerSkill) end) then
- self:doNotify("LoseSkill", json.encode{ self.id, s, true })
- end
+ self:loseFakeSkill(skill)
end
local oldKingdom = self.kingdom
diff --git a/packages/standard/hegemony.lua b/packages/standard/hegemony.lua
index a84baaf4..3c083408 100644
--- a/packages/standard/hegemony.lua
+++ b/packages/standard/hegemony.lua
@@ -229,13 +229,7 @@ function HegLogic:attachSkillToPlayers()
return
end
- -- room:handleAddLoseSkills(player, skillName, nil, false)
- player:doNotify("AddSkill", json.encode{ player.id, skillName })
-
- if skill:isInstanceOf(TriggerSkill) or table.find(skill.related_skills,
- function(s) return s:isInstanceOf(TriggerSkill) end) then
- player:doNotify("AddSkill", json.encode{ player.id, skillName, true })
- end
+ player:addFakeSkill(skill)
end
for _, p in ipairs(room.alive_players) do
diff --git a/packages/standard_cards/init.lua b/packages/standard_cards/init.lua
index 340d76ea..216c2348 100644
--- a/packages/standard_cards/init.lua
+++ b/packages/standard_cards/init.lua
@@ -413,6 +413,7 @@ local nullificationSkill = fk.CreateActiveSkill{
can_use = function()
return false
end,
+ on_use = function() RoomInstance:delay(1200) end,
on_effect = function(self, room, effect)
if effect.responseToEvent then
effect.responseToEvent.isCancellOut = true
diff --git a/src/client/replayer.cpp b/src/client/replayer.cpp
index 4f1a800b..e7ca3647 100644
--- a/src/client/replayer.cpp
+++ b/src/client/replayer.cpp
@@ -11,7 +11,12 @@ Replayer::Replayer(QObject *parent, const QString &filename) :
{
setObjectName("Replayer");
- QFile file("recording/" + filename);
+ auto s = filename;
+#ifdef Q_OS_WIN
+ if (s.startsWith("file:///"))
+ s.replace(0, 8, "file://");
+#endif
+ QFile file(QUrl(s).path());
file.open(QIODevice::ReadOnly);
QByteArray raw = file.readAll();
file.close();
diff --git a/src/server/room.cpp b/src/server/room.cpp
index 9482b421..4ba6a7e5 100644
--- a/src/server/room.cpp
+++ b/src/server/room.cpp
@@ -234,6 +234,7 @@ void Room::removePlayer(ServerPlayer *player) {
if (!gameStarted) {
// 游戏还没开始的话,直接删除这名玩家
if (players.contains(player) && !players.isEmpty()) {
+ player->setReady(false);
players.removeOne(player);
}
emit playerRemoved(player);
@@ -533,10 +534,15 @@ void Room::gameOver() {
gameStarted = false;
runned_players.clear();
// 清理所有状态不是“在线”的玩家
+ auto settings = QJsonDocument::fromJson(this->settings);
+ auto mode = settings["gameMode"].toString();
foreach (ServerPlayer *p, players) {
if (p->getState() != Player::Online) {
if (p->getState() == Player::Offline) {
- server->temporarilyBan(p->getId());
+ auto pid = p->getId();
+ addRunRate(pid, mode);
+ addRunRate(pid, mode);
+ server->temporarilyBan(pid);
}
p->deleteLater();
}
diff --git a/src/server/shell.cpp b/src/server/shell.cpp
index 72d372f4..b6f5c552 100644
--- a/src/server/shell.cpp
+++ b/src/server/shell.cpp
@@ -28,9 +28,9 @@ void Shell::helpCommand(QStringList &) {
HELP_MSG("%s: Crash the server. Useful when encounter dead loop.", "crash");
HELP_MSG("%s: List all online players.", "lsplayer");
HELP_MSG("%s: List all running rooms.", "lsroom");
- HELP_MSG("%s: Reload server config file.", "reloadconf");
+ HELP_MSG("%s: Reload server config file.", "reloadconf/r");
HELP_MSG("%s: Kick a player by his .", "kick");
- HELP_MSG("%s: Broadcast message.", "msg");
+ HELP_MSG("%s: Broadcast message.", "msg/m");
HELP_MSG("%s: Ban 1 or more accounts, IP, UUID by their .", "ban");
HELP_MSG("%s: Unban 1 or more accounts by their .", "unban");
HELP_MSG(
@@ -49,6 +49,7 @@ void Shell::helpCommand(QStringList &) {
"%s: Unban 1 or more UUID. "
"At least 1 required.",
"unbanuuid");
+ HELP_MSG("%s: reset 's password to 1234.", "resetpassword/rp");
qInfo();
qInfo("===== Package commands =====");
HELP_MSG("%s: Install a new package from .", "install");
@@ -56,7 +57,7 @@ void Shell::helpCommand(QStringList &) {
HELP_MSG("%s: List all packages.", "lspkg");
HELP_MSG("%s: Enable a package.", "enable");
HELP_MSG("%s: Disable a package.", "disable");
- HELP_MSG("%s: Upgrade a package. Leave empty to upgrade all.", "upgrade");
+ HELP_MSG("%s: Upgrade a package. Leave empty to upgrade all.", "upgrade/u");
qInfo("For more commands, check the documentation.");
#undef HELP_MSG
@@ -356,6 +357,21 @@ void Shell::reloadConfCommand(QStringList &) {
qInfo("Reloaded server config file.");
}
+void Shell::resetPasswordCommand(QStringList &list) {
+ if (list.isEmpty()) {
+ qWarning("The 'resetpassword' command needs at least 1 .");
+ return;
+ }
+
+ auto db = ServerInstance->getDatabase();
+ foreach (auto name, list) {
+ // 重置为1234
+ ExecSQL(db, QString("UPDATE userinfo SET password=\
+ 'dbdc2ad3d9625407f55674a00b58904242545bfafedac67485ac398508403ade',\
+ salt='00000000' WHERE name='%1';").arg(name));
+ }
+}
+
Shell::Shell() {
setObjectName("Shell");
signal(SIGINT, sigintHandler);
@@ -369,11 +385,13 @@ Shell::Shell() {
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;
@@ -381,6 +399,9 @@ Shell::Shell() {
handlers["banuuid"] = &Shell::banUuidCommand;
handlers["unbanuuid"] = &Shell::unbanUuidCommand;
handlers["reloadconf"] = &Shell::reloadConfCommand;
+ handlers["r"] = &Shell::reloadConfCommand;
+ handlers["resetpassword"] = &Shell::resetPasswordCommand;
+ handlers["rp"] = &Shell::resetPasswordCommand;
}
handler_map = handlers;
}
diff --git a/src/server/shell.h b/src/server/shell.h
index 7d044417..6ebea4b3 100644
--- a/src/server/shell.h
+++ b/src/server/shell.h
@@ -32,6 +32,7 @@ private:
void unbanipCommand(QStringList &);
void unbanUuidCommand(QStringList &);
void reloadConfCommand(QStringList &);
+ void resetPasswordCommand(QStringList &);
};
#endif