From 9dd4f55c863728ca113659be78c54d797f184d38 Mon Sep 17 00:00:00 2001 From: notify Date: Tue, 2 Apr 2024 01:00:10 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8D=95=E6=9C=BA=E7=83=AD=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=EF=BC=8C=E4=BB=A5=E5=8F=8ADocker=20(#336)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 以及emo公主的判定小卡换图 --------- Co-authored-by: seven <786852516@qq.com> --- Fk/Cheat/PlayerDetail.qml | 39 ++++++++++----- docker/Dockerfile | 40 ++++++++------- docker/docker-entrypoint.sh | 29 +++++++++++ image/card/delayedTrick/unknown.png | Bin 2998 -> 3669 bytes lua/client/client_util.lua | 4 ++ lua/core/engine.lua | 73 +++++++++++++++++++++++++++- lua/server/ai/random_ai.lua | 3 ++ lua/server/request.lua | 6 +++ lua/server/scheduler.lua | 4 ++ src/CMakeLists.txt | 22 +++++++++ src/client/client.cpp | 51 ++++++++++++++++++- src/client/client.h | 7 +++ src/main.cpp | 19 ++++---- src/network/router.cpp | 4 ++ src/network/router.h | 1 + src/server/roomthread.cpp | 13 +++++ src/server/roomthread.h | 1 + src/swig/server.i | 2 + 18 files changed, 275 insertions(+), 43 deletions(-) create mode 100644 docker/docker-entrypoint.sh diff --git a/Fk/Cheat/PlayerDetail.qml b/Fk/Cheat/PlayerDetail.qml index 38088397..517c60ec 100644 --- a/Fk/Cheat/PlayerDetail.qml +++ b/Fk/Cheat/PlayerDetail.qml @@ -3,6 +3,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts +import Fk.Common import Fk.Pages import Fk.RoomElement @@ -22,18 +23,29 @@ Flickable { width: parent.width - 40 x: 20 - // TODO: player details - Text { - id: screenName - font.pixelSize: 18 - color: "#E4D5A0" - } + RowLayout { + spacing: 8 + Avatar { + id: avatar + Layout.preferredWidth: 56 + Layout.preferredHeight: 56 + general: "diaochan" + } - Text { - id: playerGameData - Layout.fillWidth: true - font.pixelSize: 18 - color: "#E4D5A0" + ColumnLayout { + Text { + id: screenName + font.pixelSize: 18 + color: "#E4D5A0" + } + + Text { + id: playerGameData + Layout.fillWidth: true + font.pixelSize: 18 + color: "#E4D5A0" + } + } } RowLayout { @@ -163,6 +175,7 @@ Flickable { if (id === 0) return; root.pid = id; + avatar.general = extra_data.photo.avatar; screenName.text = extra_data.photo.screenName; mainChara.name = extra_data.photo.general; deputyChara.name = extra_data.photo.deputyGeneral; @@ -182,9 +195,9 @@ Flickable { const h = (totalTime / 3600).toFixed(2); const m = Math.floor(totalTime / 60); if (m < 100) { - playerGameData.text += " " + luatr("TotalGameTime: %1 min").arg(m); + screenName.text += " (" + luatr("TotalGameTime: %1 min").arg(m) + ")"; } else { - playerGameData.text += " " + luatr("TotalGameTime: %1 h").arg(h); + screenName.text += " (" + luatr("TotalGameTime: %1 h").arg(h) + ")"; } } diff --git a/docker/Dockerfile b/docker/Dockerfile index 60ce0e88..b2766c3a 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,25 +1,29 @@ -FROM debian -USER root +FROM linuxcontainers/debian-slim:latest +# install dependencies +RUN apt update -y && apt upgrade -y && \ + apt install -y \ + gcc g++ cmake \ + liblua5.4-dev libsqlite3-dev libreadline-dev libssl-dev libgit2-dev swig qt6-base-dev qt6-tools-dev-tools \ + gosu && \ + apt clean -y && \ + rm -rf /var/lib/apt/lists/* + +# prepare source code COPY . /FreeKill -#update apt dependencies -RUN apt update -y && apt upgrade -y +# compile and install +RUN mkdir -p /FreeKill/build && \ + cd /FreeKill/build && cp -r /usr/include/lua5.4/* ../include && cmake .. -DFK_SERVER_ONLY= && make && \ + cd /FreeKill && cmake --install build --config Release && \ + cp /FreeKill/docker/docker-entrypoint.sh / && chmod +x /docker-entrypoint.sh && \ + mkdir /data && \ + cd / && rm -rf /FreeKill -#install compile tools -RUN apt install -y gcc g++ cmake -RUN apt install -y liblua5.4-dev libsqlite3-dev libreadline-dev libssl-dev libgit2-dev swig qt6-base-dev qt6-tools-dev-tools - -#change workdir to FreeKill -WORKDIR /FreeKill - -#compile source code -RUN mkdir build && cd build && cp -r /usr/include/lua5.4/* ../include && cmake .. -DFK_SERVER_ONLY= -RUN cd build && make - -#build soft link -RUN ln -s build/FreeKill +WORKDIR /data EXPOSE 9527 -ENTRYPOINT ["/FreeKill/FreeKill", "-s"] +ENTRYPOINT ["/docker-entrypoint.sh"] + +CMD ["FreeKill", "-s"] diff --git a/docker/docker-entrypoint.sh b/docker/docker-entrypoint.sh new file mode 100644 index 00000000..b2ed6b45 --- /dev/null +++ b/docker/docker-entrypoint.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +USER_ID=${LOCAL_USER_ID:-1000} + +if [ "${1#-}" != "$1" ]; then + set -- FreeKill -s "$@" +fi + +if [ "$1" = 'FreeKill' -a "$(id -u)" = '0' ]; then + id -u freekill >&/dev/null + if [ $? -ne 0 ]; then + useradd --shell /bin/bash -u $USER_ID -o -c "" -m freekill + usermod -aG root freekill + export HOME=/home/freekill + mkdir -p $HOME/.local/share + ln -s /data $HOME/.local/share/FreeKill + chown -R freekill:freekill $HOME + if [ ! -d "/data/server" ]; then + cp -r /usr/local/share/FreeKill/server /data + fi + if [ ! -d "/data/packages" ]; then + cp -r /usr/local/share/FreeKill/packages /data + fi + fi + chown -R freekill /data + exec gosu freekill "$0" "$@" +fi + +exec "$@" diff --git a/image/card/delayedTrick/unknown.png b/image/card/delayedTrick/unknown.png index 0c0f0c3704ed05b834a4f061a1287b0bc6661a0d..4731fd9b19703fbeb9b43be72bf4c75be56f164c 100644 GIT binary patch literal 3669 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 diff --git a/lua/client/client_util.lua b/lua/client/client_util.lua index a92531eb..27cbc345 100644 --- a/lua/client/client_util.lua +++ b/lua/client/client_util.lua @@ -784,4 +784,8 @@ function GetMiniGame(gtype, p, data) } end +function ReloadPackage(path) + Fk:reloadPackage(path) +end + dofile "lua/client/i18n/init.lua" diff --git a/lua/core/engine.lua b/lua/core/engine.lua index 1585aa3d..b3023764 100644 --- a/lua/core/engine.lua +++ b/lua/core/engine.lua @@ -47,7 +47,6 @@ function Engine:initialize() end Fk = self - self.extensions = { ["standard"] = { "standard" }, ["standard_cards"] = { "standard_cards" }, @@ -123,6 +122,76 @@ function Engine:loadPackage(pack) self:addGameModes(pack.game_modes) end +-- Don't do this +local package = package +function Engine:reloadPackage(path) + path = path:sub(1, #path - 4) + local oldPkg = package.loaded[path] + package.loaded[path] = nil + local ok, err = pcall(require, path) + if not ok then + package.loaded[path] = oldPkg + print("reload failed:", err) + return + end + + -- 阉割版重载机制,反正单机用 + local function replace(t, skill) + if not t then return end + for k, s in pairs(t) do + if s.name == skill.name then + t[k] = skill + break + end + end + end + + local function f(p) + self.packages[p.name] = p + local room = Fk:currentRoom() + local skills = p:getSkills() + local related = {} + for _, skill in ipairs(skills) do + table.insertTableIfNeed(related, skill.related_skills) + end + table.insertTableIfNeed(skills, related) + + for _, skill in ipairs(skills) do + if self.skills[skill.name].class ~= skill.class then + fk.qCritical("cannot change class of skill: " .. skill.name) + goto CONTINUE + end + self.skills[skill.name] = skill + if skill:isInstanceOf(TriggerSkill) and RoomInstance then + local logic = room.logic + for _, event in ipairs(skill.refresh_events) do + replace(logic.refresh_skill_table[event], skill) + end + for _, event in ipairs(skill.events) do + replace(logic.skill_table[event], skill) + end + end + if skill:isInstanceOf(StatusSkill) then + replace(room.status_skills[skill.class], skill) + end + + for _, p in ipairs(room.players) do + replace(p.player_skills, skill) + end + ::CONTINUE:: + end + end + + local pkg = package.loaded[path] + if type(pkg) ~= "table" then return end + if pkg.class and pkg:isInstanceOf(Package) then + f(pkg) + elseif path:endsWith("init") and not path:find("/ai/") then + for _, p in ipairs(pkg) do f(p) end + end +end + + --- 加载所有拓展包。 --- --- Engine会在packages/下搜索所有含有init.lua的文件夹,并把它们作为拓展包加载进来。 @@ -215,7 +284,7 @@ end function Engine:addSkill(skill) assert(skill.class:isSubclassOf(Skill)) if self.skills[skill.name] ~= nil then - error(string.format("Duplicate skill %s detected", skill.name)) + fk.qWarning(string.format("Duplicate skill %s detected", skill.name)) end self.skills[skill.name] = skill diff --git a/lua/server/ai/random_ai.lua b/lua/server/ai/random_ai.lua index cfb12ac9..6a5ca098 100644 --- a/lua/server/ai/random_ai.lua +++ b/lua/server/ai/random_ai.lua @@ -10,6 +10,8 @@ function RandomAI:useActiveSkill(skill, card) local room = self.room local player = self.player + if skill:isInstanceOf(ViewAsSkill) then return "" end + local filter_func = skill.cardFilter if card then filter_func = Util.FalseFunc @@ -68,6 +70,7 @@ function RandomAI:useVSSkill(skill, pattern, cancelable, extra_data) local player = self.player local room = self.room local precondition + if not skill then return nil end if self.command == "PlayCard" then precondition = skill:enabledAtPlay(player) diff --git a/lua/server/request.lua b/lua/server/request.lua index 2d36437d..1b9ff419 100644 --- a/lua/server/request.lua +++ b/lua/server/request.lua @@ -181,6 +181,12 @@ request_handlers["newroom"] = function(s, id) s:registerRoom(id) end +request_handlers["reloadpackage"] = function(room, id, reqlist) + if not IsConsoleStart() then return end + local path = reqlist[3] + Fk:reloadPackage(path) +end + -- 处理异步请求的协程,本身也是个死循环就是了。 -- 为了适应调度器,目前又暂且将请求分为“耗时请求”和不耗时请求。 -- 耗时请求处理后会立刻挂起。不耗时的请求则会不断处理直到请求队列空后再挂起。 diff --git a/lua/server/scheduler.lua b/lua/server/scheduler.lua index 2c1a16dd..e1bf22d3 100644 --- a/lua/server/scheduler.lua +++ b/lua/server/scheduler.lua @@ -154,3 +154,7 @@ function InitScheduler(_thread) requestRoom.thread = _thread Pcall(mainLoop) end + +function IsConsoleStart() + return requestRoom.thread:isConsoleStart() +end diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c74fbadc..f63910b2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -97,3 +97,25 @@ target_link_libraries(FreeKill PRIVATE ) install(TARGETS FreeKill DESTINATION bin) +install(DIRECTORY + ${PROJECT_SOURCE_DIR}/audio + ${PROJECT_SOURCE_DIR}/fonts + ${PROJECT_SOURCE_DIR}/image + ${PROJECT_SOURCE_DIR}/lua + ${PROJECT_SOURCE_DIR}/packages + ${PROJECT_SOURCE_DIR}/Fk + ${PROJECT_SOURCE_DIR}/server + DESTINATION share/FreeKill +) +install(FILES + ${PROJECT_SOURCE_DIR}/fk_ver + DESTINATION share/FreeKill +) + +if (NOT DEFINED FK_SERVER_ONLY) + install(FILES + ${CMAKE_BINARY_DIR}/zh_CN.qm + ${CMAKE_BINARY_DIR}/en_US.qm + DESTINATION share/FreeKill + ) +endif() diff --git a/src/client/client.cpp b/src/client/client.cpp index e4cdf03f..f2dc5e4c 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -3,7 +3,11 @@ #include "client.h" #include "client_socket.h" #include "clientplayer.h" +#include "qmlbackend.h" #include "util.h" +#include "server.h" +#include +#include Client *ClientInstance = nullptr; ClientPlayer *Self = nullptr; @@ -78,7 +82,10 @@ void Client::changeSelf(int id) { lua_State *Client::getLuaState() { return L; } -void Client::installAESKey(const QByteArray &key) { router->installAESKey(key); } +void Client::installAESKey(const QByteArray &key) { + startWatchFiles(); + router->installAESKey(key); +} void Client::saveRecord(const QString &json, const QString &fname) { if (!QDir("recording").exists()) { @@ -90,6 +97,48 @@ void Client::saveRecord(const QString &json, const QString &fname) { c.close(); } +bool Client::isConsoleStart() const { + if (!ClientInstance || !ServerInstance) { + return false; + } + + return router->isConsoleStart(); +} + +void Client::startWatchFiles() { + if (!isConsoleStart()) return; + if (!fsWatcher.files().empty()) return; + QFile flist("flist.txt"); + if (!flist.open(QIODevice::ReadOnly)) { + qCritical("Cannot open flist.txt. Won't watch files."); + fsWatcher.addPath("fk_ver"); // dummy + } + auto md5pairs = flist.readAll().split(';'); + foreach (auto md5, md5pairs) { + if (md5.isEmpty()) continue; + auto fname = md5.split('=')[0]; + if (fname.startsWith("packages") && fname.endsWith(".lua")) { + fsWatcher.addPath(fname); + } + } + connect(&fsWatcher, &QFileSystemWatcher::fileChanged, this, + &Client::updateLuaFiles); +} + void Client::processReplay(const QString &c, const QString &j) { callLua(c, j); } + +void Client::updateLuaFiles(const QString &path) { + if (!isConsoleStart()) return; + Backend->showToast(tr("File %1 changed, reloading...").arg(path)); + QThread::msleep(100); + Backend->callLuaFunction("ReloadPackage", { path }); + ClientInstance->notifyServer("PushRequest", + QString("reloadpackage,%1").arg(path)); + + // according to QT documentation + if (!fsWatcher.files().contains(path) && QFile::exists(path)) { + fsWatcher.addPath(path); + } +} diff --git a/src/client/client.h b/src/client/client.h index a98e4ba1..f5d0d7ab 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -5,6 +5,7 @@ #include "router.h" #include "clientplayer.h" +#include #ifndef FK_SERVER_ONLY #include "qmlbackend.h" @@ -34,18 +35,24 @@ public: void saveRecord(const QString &json, const QString &fname); + bool isConsoleStart() const; + void startWatchFiles(); signals: void error_message(const QString &msg); public slots: void processReplay(const QString &, const QString &); +private slots: + void updateLuaFiles(const QString &path); + private: Router *router; QMap players; ClientPlayer *self; lua_State *L; + QFileSystemWatcher fsWatcher; }; extern Client *ClientInstance; diff --git a/src/main.cpp b/src/main.cpp index fb2fd807..e9c7a453 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -173,6 +173,16 @@ void fkMsgHandler(QtMsgType type, const QMessageLogContext &context, int main(int argc, char *argv[]) { // 初始化一下各种杂项信息 QThread::currentThread()->setObjectName("Main"); + + qInstallMessageHandler(fkMsgHandler); + QCoreApplication *app; + QCoreApplication::setApplicationName("FreeKill"); + QCoreApplication::setApplicationVersion(FK_VERSION); + +#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) + prepareForLinux(); +#endif + if (!info_log) { info_log = fopen("freekill.server.info.log", "w+"); if (!info_log) { @@ -186,15 +196,6 @@ int main(int argc, char *argv[]) { } } - qInstallMessageHandler(fkMsgHandler); - QCoreApplication *app; - QCoreApplication::setApplicationName("FreeKill"); - QCoreApplication::setApplicationVersion(FK_VERSION); - -#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) - prepareForLinux(); -#endif - #ifndef FK_CLIENT_ONLY // 分析命令行,如果有 -s 或者 --server 就在命令行直接开服务器 QCommandLineParser parser; diff --git a/src/network/router.cpp b/src/network/router.cpp index 38c96437..4de18c85 100644 --- a/src/network/router.cpp +++ b/src/network/router.cpp @@ -53,6 +53,10 @@ void Router::installAESKey(const QByteArray &key) { socket->installAESKey(key); } +bool Router::isConsoleStart() const { + return socket->peerAddress() == "127.0.0.1"; +} + #ifndef FK_CLIENT_ONLY void Router::setReplyReadySemaphore(QSemaphore *semaphore) { extraReplyReadySemaphore = semaphore; diff --git a/src/network/router.h b/src/network/router.h index 62048a6b..7c8841b7 100644 --- a/src/network/router.h +++ b/src/network/router.h @@ -32,6 +32,7 @@ public: void setSocket(ClientSocket *socket); void removeSocket(); void installAESKey(const QByteArray &key); + bool isConsoleStart() const; #ifndef FK_CLIENT_ONLY void setReplyReadySemaphore(QSemaphore *semaphore); diff --git a/src/server/roomthread.cpp b/src/server/roomthread.cpp index a193576a..104d592c 100644 --- a/src/server/roomthread.cpp +++ b/src/server/roomthread.cpp @@ -4,6 +4,10 @@ #include "server.h" #include "util.h" +#ifndef FK_SERVER_ONLY +#include "client.h" +#endif + RoomThread::RoomThread(Server *m_server) { setObjectName("Room"); this->m_server = m_server; @@ -105,3 +109,12 @@ void RoomThread::tryTerminate() { bool RoomThread::isTerminated() const { return terminated; } + +bool RoomThread::isConsoleStart() const { +#ifndef FK_SERVER_ONLY + if (!ClientInstance) return false; + return ClientInstance->isConsoleStart(); +#else + return false; +#endif +} diff --git a/src/server/roomthread.h b/src/server/roomthread.h index f8baf4c3..15cd1964 100644 --- a/src/server/roomthread.h +++ b/src/server/roomthread.h @@ -31,6 +31,7 @@ class RoomThread : public QThread { void tryTerminate(); bool isTerminated() const; + bool isConsoleStart() const; protected: virtual void run(); diff --git a/src/swig/server.i b/src/swig/server.i index 3f73d8c6..82908a2b 100644 --- a/src/swig/server.i +++ b/src/swig/server.i @@ -39,6 +39,8 @@ public: void trySleep(int ms); bool isTerminated() const; + + bool isConsoleStart() const; }; %{