Wasm (#36)
* compile with wasm * pack into qrc * disable colorized msg for browser and cmd.exe * run lua in wasm * run the game * font & pixmap anim * special init page for web * doc for compile wasm
This commit is contained in:
parent
f434e9ee9b
commit
fb425e15fb
|
@ -2,8 +2,10 @@ cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
project(FreeKill VERSION 0.0.1)
|
project(FreeKill VERSION 0.0.1)
|
||||||
|
|
||||||
|
if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
||||||
include_directories(fkparse/src)
|
include_directories(fkparse/src)
|
||||||
add_subdirectory(fkparse)
|
add_subdirectory(fkparse)
|
||||||
|
endif ()
|
||||||
|
|
||||||
find_package(Qt6 REQUIRED COMPONENTS
|
find_package(Qt6 REQUIRED COMPONENTS
|
||||||
Gui
|
Gui
|
||||||
|
@ -31,15 +33,38 @@ include_directories(src/network)
|
||||||
include_directories(src/server)
|
include_directories(src/server)
|
||||||
include_directories(src/ui)
|
include_directories(src/ui)
|
||||||
|
|
||||||
|
if (${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
||||||
|
# Fix include problem
|
||||||
|
include_directories("/usr/include/openssl-1.1/")
|
||||||
|
endif()
|
||||||
|
|
||||||
file(GLOB SWIG_FILES "${PROJECT_SOURCE_DIR}/src/swig/*.i")
|
file(GLOB SWIG_FILES "${PROJECT_SOURCE_DIR}/src/swig/*.i")
|
||||||
|
if (${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
||||||
|
set(SWIG_SOURCE ${PROJECT_SOURCE_DIR}/src/swig/freekill-wasm.i)
|
||||||
|
else ()
|
||||||
|
set(SWIG_SOURCE ${PROJECT_SOURCE_DIR}/src/swig/freekill.i)
|
||||||
|
endif ()
|
||||||
|
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT ${PROJECT_SOURCE_DIR}/src/swig/freekill-wrap.cxx
|
OUTPUT ${PROJECT_SOURCE_DIR}/src/swig/freekill-wrap.cxx
|
||||||
DEPENDS ${SWIG_FILES}
|
DEPENDS ${SWIG_FILES}
|
||||||
COMMENT "Generating freekill-wrap.cxx"
|
COMMENT "Generating freekill-wrap.cxx"
|
||||||
COMMAND swig -c++ -lua -Wall -o
|
COMMAND swig -c++ -lua -Wall -o
|
||||||
${PROJECT_SOURCE_DIR}/src/swig/freekill-wrap.cxx
|
${PROJECT_SOURCE_DIR}/src/swig/freekill-wrap.cxx
|
||||||
${PROJECT_SOURCE_DIR}/src/swig/freekill.i
|
${SWIG_SOURCE}
|
||||||
)
|
)
|
||||||
|
|
||||||
qt_add_executable(FreeKill)
|
qt_add_executable(FreeKill)
|
||||||
|
|
||||||
|
if (${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
||||||
|
file(GLOB_RECURSE FK_RESOURCE_FILES
|
||||||
|
RELATIVE ${PROJECT_SOURCE_DIR}
|
||||||
|
*.lua *.qml *.js *.png *.jpg *.mp3
|
||||||
|
)
|
||||||
|
list(APPEND FK_RESOURCE_FILES "fonts/FZLBGBK.ttf")
|
||||||
|
qt_add_resources(FreeKill "qrc"
|
||||||
|
PREFIX "/"
|
||||||
|
FILES ${FK_RESOURCE_FILES}
|
||||||
|
)
|
||||||
|
endif()
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
|
|
|
@ -91,3 +91,30 @@ ___
|
||||||
## 编译安卓版
|
## 编译安卓版
|
||||||
|
|
||||||
用Qt安装器装好Android库,然后配置一下android-sdk就能编译了。
|
用Qt安装器装好Android库,然后配置一下android-sdk就能编译了。
|
||||||
|
|
||||||
|
___
|
||||||
|
|
||||||
|
## WASM下编译
|
||||||
|
|
||||||
|
WASM大概就是能在浏览器中跑C++。编译用Qt Creator即可。
|
||||||
|
|
||||||
|
### 1. 条件与局限性
|
||||||
|
|
||||||
|
如果程序运行在网页上的话,那么理应只有客户端,然后提供网页的服务器上自然也运行着一个后端服务器。所以说在编译时应该舍弃掉服务端相关的代码。因此依赖库就不再需要sqlite3。
|
||||||
|
|
||||||
|
总之是编译个纯客户端的FK。
|
||||||
|
|
||||||
|
### 2. 编译OpenSSL
|
||||||
|
|
||||||
|
进入OpenSSL的src目录,然后
|
||||||
|
|
||||||
|
$ ./config -no-asm -no-engine -no-dso
|
||||||
|
$ emmake make -j8 build_generated libssl.a libcrypto.a
|
||||||
|
|
||||||
|
编译Lua的话直接emmake make就行了,总之库已经传到仓库了。
|
||||||
|
|
||||||
|
### 3. 部署资源文件
|
||||||
|
|
||||||
|
由于CMake中`file(GLOB_RECURSE)`所带来的缺陷,每当资源文件变动时,需要手动更新。
|
||||||
|
|
||||||
|
把构建目录中的.rcc目录删掉然后重新执行CMake->make即可。每次编译资源文件总要消耗相当多的时间。
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -1,5 +1,4 @@
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import Qt.labs.folderlistmodel
|
|
||||||
import "../skin-bank.js" as SkinBank
|
import "../skin-bank.js" as SkinBank
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
|
@ -18,12 +17,8 @@ Item {
|
||||||
width: childrenRect.width
|
width: childrenRect.width
|
||||||
height: childrenRect.height
|
height: childrenRect.height
|
||||||
|
|
||||||
FolderListModel {
|
property string folder: SkinBank.PIXANIM_DIR + source
|
||||||
id: fileModel
|
property int fileModel
|
||||||
folder: SkinBank.PIXANIM_DIR + source
|
|
||||||
nameFilters: ["*.png"]
|
|
||||||
showDirs: false
|
|
||||||
}
|
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
id: frames
|
id: frames
|
||||||
|
@ -35,7 +30,7 @@ Item {
|
||||||
onStatusChanged: {
|
onStatusChanged: {
|
||||||
if (status == Image.Ready) {
|
if (status == Image.Ready) {
|
||||||
loadedFrameCount++;
|
loadedFrameCount++;
|
||||||
if (loadedFrameCount == fileModel.count)
|
if (loadedFrameCount == fileModel)
|
||||||
root.loaded();
|
root.loaded();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,8 +47,8 @@ Item {
|
||||||
interval: 50
|
interval: 50
|
||||||
repeat: true
|
repeat: true
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if (currentFrame >= fileModel.count) {
|
if (currentFrame >= fileModel) {
|
||||||
frames.itemAt(fileModel.count - 1).visible = false;
|
frames.itemAt(fileModel - 1).visible = false;
|
||||||
if (loop) {
|
if (loop) {
|
||||||
currentFrame = 0;
|
currentFrame = 0;
|
||||||
} else {
|
} else {
|
||||||
|
@ -73,7 +68,7 @@ Item {
|
||||||
|
|
||||||
function start()
|
function start()
|
||||||
{
|
{
|
||||||
if (loadedFrameCount == fileModel.count) {
|
if (loadedFrameCount == fileModel) {
|
||||||
timer.start();
|
timer.start();
|
||||||
} else {
|
} else {
|
||||||
root.loaded.connect(function(){
|
root.loaded.connect(function(){
|
||||||
|
@ -86,4 +81,8 @@ Item {
|
||||||
{
|
{
|
||||||
timer.stop();
|
timer.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
fileModel = Backend.ls(folder).length;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -170,7 +170,14 @@ function moveCards(moves) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function setEmotion(id, emotion) {
|
function setEmotion(id, emotion) {
|
||||||
let path = (SkinBank.PIXANIM_DIR + emotion).replace("file://", "");
|
let path;
|
||||||
|
if (OS === "Win") {
|
||||||
|
// Windows: file:/C:/xxx/xxxx
|
||||||
|
path = (SkinBank.PIXANIM_DIR + emotion).replace("file:/", "");
|
||||||
|
} else {
|
||||||
|
path = (SkinBank.PIXANIM_DIR + emotion).replace("file://", "");
|
||||||
|
}
|
||||||
|
|
||||||
if (!Backend.exists(path)) {
|
if (!Backend.exists(path)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
scale: 2
|
||||||
|
|
||||||
|
// Change this to your server's IP or domain name
|
||||||
|
property string server_addr: "127.0.0.1:9530"
|
||||||
|
|
||||||
|
Frame {
|
||||||
|
id: join_server
|
||||||
|
anchors.centerIn: parent
|
||||||
|
background: Rectangle {
|
||||||
|
color: "#88888888"
|
||||||
|
radius: 2
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
spacing: 8
|
||||||
|
TextField {
|
||||||
|
id: screenNameEdit
|
||||||
|
text: "player"
|
||||||
|
onTextChanged: {
|
||||||
|
passwordEdit.text = "";
|
||||||
|
let data = config.savedPassword[server_addr.editText];
|
||||||
|
if (data) {
|
||||||
|
if (text === data.username) {
|
||||||
|
passwordEdit.text = data.shorten_password;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TextField {
|
||||||
|
id: passwordEdit
|
||||||
|
text: ""
|
||||||
|
echoMode: TextInput.Password
|
||||||
|
passwordCharacter: "*"
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
text: "Login"
|
||||||
|
enabled: passwordEdit.text !== ""
|
||||||
|
onClicked: {
|
||||||
|
config.serverAddr = server_addr;
|
||||||
|
config.screenName = screenNameEdit.text;
|
||||||
|
config.password = passwordEdit.text;
|
||||||
|
mainWindow.busy = true;
|
||||||
|
Backend.joinServer(server_addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
config.loadConf();
|
||||||
|
|
||||||
|
let data = config.savedPassword[config.lastLoginServer];
|
||||||
|
screenNameEdit.text = data.username;
|
||||||
|
passwordEdit.text = data.shorten_password;
|
||||||
|
}
|
||||||
|
}
|
|
@ -37,11 +37,12 @@ Item {
|
||||||
StackView {
|
StackView {
|
||||||
id: mainStack
|
id: mainStack
|
||||||
visible: !mainWindow.busy
|
visible: !mainWindow.busy
|
||||||
initialItem: init
|
initialItem: OS !== "Web" ? init : webinit
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
}
|
}
|
||||||
|
|
||||||
Component { id: init; Init {} }
|
Component { id: init; Init {} }
|
||||||
|
Component { id: webinit; WebInit {} }
|
||||||
Component { id: lobby; Lobby {} }
|
Component { id: lobby; Lobby {} }
|
||||||
Component { id: generalsOverview; GeneralsOverview {} }
|
Component { id: generalsOverview; GeneralsOverview {} }
|
||||||
Component { id: cardsOverview; CardsOverview {} }
|
Component { id: cardsOverview; CardsOverview {} }
|
||||||
|
@ -152,7 +153,7 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
if (!Android) {
|
if (OS !== "Android" && OS !== "Web") {
|
||||||
width = config.winWidth;
|
width = config.winWidth;
|
||||||
height = config.winHeight;
|
height = config.winHeight;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ set(freekill_HEADERS
|
||||||
"ui/qmlbackend.h"
|
"ui/qmlbackend.h"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set(FKP_LIB fkparse)
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
set(LUA_LIB ${PROJECT_SOURCE_DIR}/lib/win/lua54.dll)
|
set(LUA_LIB ${PROJECT_SOURCE_DIR}/lib/win/lua54.dll)
|
||||||
set(SQLITE3_LIB ${PROJECT_SOURCE_DIR}/lib/win/sqlite3.dll)
|
set(SQLITE3_LIB ${PROJECT_SOURCE_DIR}/lib/win/sqlite3.dll)
|
||||||
|
@ -40,6 +41,19 @@ elseif (ANDROID)
|
||||||
QT_ANDROID_PACKAGE_SOURCE_DIR ${PROJECT_SOURCE_DIR}/android
|
QT_ANDROID_PACKAGE_SOURCE_DIR ${PROJECT_SOURCE_DIR}/android
|
||||||
QT_ANDROID_EXTRA_LIBS "${LUA_LIB};${SQLITE3_LIB};${CRYPTO_LIB}"
|
QT_ANDROID_EXTRA_LIBS "${LUA_LIB};${SQLITE3_LIB};${CRYPTO_LIB}"
|
||||||
)
|
)
|
||||||
|
elseif (${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
||||||
|
# WASM
|
||||||
|
list(REMOVE_ITEM freekill_SRCS
|
||||||
|
"network/server_socket.cpp"
|
||||||
|
#"network/client_socket.cpp"
|
||||||
|
#"network/router.cpp"
|
||||||
|
"server/server.cpp"
|
||||||
|
"server/serverplayer.cpp"
|
||||||
|
"server/room.cpp"
|
||||||
|
)
|
||||||
|
set(FKP_LIB "")
|
||||||
|
set(LUA_LIB ${PROJECT_SOURCE_DIR}/lib/wasm/liblua.a)
|
||||||
|
set(CRYPTO_LIB ${PROJECT_SOURCE_DIR}/lib/wasm/libcrypto.a)
|
||||||
else ()
|
else ()
|
||||||
set(LUA_LIB lua5.4)
|
set(LUA_LIB lua5.4)
|
||||||
set(SQLITE3_LIB sqlite3)
|
set(SQLITE3_LIB sqlite3)
|
||||||
|
@ -57,7 +71,7 @@ target_link_libraries(FreeKill PRIVATE
|
||||||
${SQLITE3_LIB}
|
${SQLITE3_LIB}
|
||||||
${CRYPTO_LIB}
|
${CRYPTO_LIB}
|
||||||
${READLINE_LIB}
|
${READLINE_LIB}
|
||||||
fkparse
|
${FKP_LIB}
|
||||||
Qt6::Qml
|
Qt6::Qml
|
||||||
Qt6::Gui
|
Qt6::Gui
|
||||||
Qt6::Widgets
|
Qt6::Widgets
|
||||||
|
|
|
@ -61,6 +61,7 @@ void Dumpstack(lua_State *L)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef Q_OS_WASM
|
||||||
sqlite3 *OpenDatabase(const QString &filename)
|
sqlite3 *OpenDatabase(const QString &filename)
|
||||||
{
|
{
|
||||||
sqlite3 *ret;
|
sqlite3 *ret;
|
||||||
|
@ -151,6 +152,7 @@ RSA *InitServerRSA() {
|
||||||
fclose(keyFile);
|
fclose(keyFile);
|
||||||
return rsa;
|
return rsa;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void writeFileMD5(QFile &dest, const QString &fname) {
|
static void writeFileMD5(QFile &dest, const QString &fname) {
|
||||||
QFile f(fname);
|
QFile f(fname);
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
lua_State *CreateLuaState();
|
lua_State *CreateLuaState();
|
||||||
bool DoLuaScript(lua_State *L, const char *script);
|
bool DoLuaScript(lua_State *L, const char *script);
|
||||||
|
|
||||||
|
#ifndef Q_OS_WASM
|
||||||
sqlite3 *OpenDatabase(const QString &filename = "./server/users.db");
|
sqlite3 *OpenDatabase(const QString &filename = "./server/users.db");
|
||||||
QJsonObject SelectFromDatabase(sqlite3 *db, const QString &sql);
|
QJsonObject SelectFromDatabase(sqlite3 *db, const QString &sql);
|
||||||
// For Lua
|
// For Lua
|
||||||
|
@ -14,6 +15,7 @@ void ExecSQL(sqlite3 *db, const QString &sql);
|
||||||
void CloseDatabase(sqlite3 *db);
|
void CloseDatabase(sqlite3 *db);
|
||||||
|
|
||||||
RSA *InitServerRSA();
|
RSA *InitServerRSA();
|
||||||
|
#endif
|
||||||
|
|
||||||
QString calcFileMD5();
|
QString calcFileMD5();
|
||||||
|
|
||||||
|
|
40
src/main.cpp
40
src/main.cpp
|
@ -1,5 +1,7 @@
|
||||||
#include "qmlbackend.h"
|
#include "qmlbackend.h"
|
||||||
|
#ifndef Q_OS_WASM
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
|
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
|
||||||
#include "shell.h"
|
#include "shell.h"
|
||||||
|
@ -11,8 +13,9 @@
|
||||||
|
|
||||||
#include <QSplashScreen>
|
#include <QSplashScreen>
|
||||||
#include <QScreen>
|
#include <QScreen>
|
||||||
|
#include <QFileDialog>
|
||||||
|
|
||||||
#ifdef Q_OS_ANDROID
|
#if defined(Q_OS_ANDROID) || defined(Q_OS_WASM)
|
||||||
static bool copyPath(const QString &srcFilePath, const QString &tgtFilePath)
|
static bool copyPath(const QString &srcFilePath, const QString &tgtFilePath)
|
||||||
{
|
{
|
||||||
QFileInfo srcFileInfo(srcFilePath);
|
QFileInfo srcFileInfo(srcFilePath);
|
||||||
|
@ -48,19 +51,19 @@ void fkMsgHandler(QtMsgType type, const QMessageLogContext &context, const QStri
|
||||||
auto threadName = QThread::currentThread()->objectName().toLatin1().constData();
|
auto threadName = QThread::currentThread()->objectName().toLatin1().constData();
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case QtDebugMsg:
|
case QtDebugMsg:
|
||||||
fprintf(stderr, "[%s/\e[1;30mDEBUG\e[0m] %s\n", threadName, localMsg.constData());
|
fprintf(stderr, "[%s/DEBUG] %s\n", threadName, localMsg.constData());
|
||||||
break;
|
break;
|
||||||
case QtInfoMsg:
|
case QtInfoMsg:
|
||||||
fprintf(stderr, "[%s/\e[1;32mINFO\e[0m] %s\n", threadName, localMsg.constData());
|
fprintf(stderr, "[%s/INFO] %s\n", threadName, localMsg.constData());
|
||||||
break;
|
break;
|
||||||
case QtWarningMsg:
|
case QtWarningMsg:
|
||||||
fprintf(stderr, "[%s/\e[1;33mWARNING\e[0m] %s\n", threadName, localMsg.constData());
|
fprintf(stderr, "[%s/WARNING] %s\n", threadName, localMsg.constData());
|
||||||
break;
|
break;
|
||||||
case QtCriticalMsg:
|
case QtCriticalMsg:
|
||||||
fprintf(stderr, "[%s/\e[1;31mCRITICAL\e[0m] %s\n", threadName, localMsg.constData());
|
fprintf(stderr, "[%s/CRITICAL] %s\n", threadName, localMsg.constData());
|
||||||
break;
|
break;
|
||||||
case QtFatalMsg:
|
case QtFatalMsg:
|
||||||
fprintf(stderr, "[%s/\e[1;31mFATAL\e[0m] %s\n", threadName, localMsg.constData());
|
fprintf(stderr, "[%s/FATAL] %s\n", threadName, localMsg.constData());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,6 +76,7 @@ int main(int argc, char *argv[])
|
||||||
QCoreApplication::setApplicationName("FreeKill");
|
QCoreApplication::setApplicationName("FreeKill");
|
||||||
QCoreApplication::setApplicationVersion("Alpha 0.0.1");
|
QCoreApplication::setApplicationVersion("Alpha 0.0.1");
|
||||||
|
|
||||||
|
#ifndef Q_OS_WASM
|
||||||
QCommandLineParser parser;
|
QCommandLineParser parser;
|
||||||
parser.setApplicationDescription("FreeKill server");
|
parser.setApplicationDescription("FreeKill server");
|
||||||
parser.addHelpOption();
|
parser.addHelpOption();
|
||||||
|
@ -105,6 +109,9 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
return app->exec();
|
return app->exec();
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
copyPath(":/", QDir::currentPath());
|
||||||
|
#endif
|
||||||
|
|
||||||
app = new QApplication(argc, argv);
|
app = new QApplication(argc, argv);
|
||||||
|
|
||||||
|
@ -132,19 +139,32 @@ int main(int argc, char *argv[])
|
||||||
backend.setEngine(engine);
|
backend.setEngine(engine);
|
||||||
|
|
||||||
engine->rootContext()->setContextProperty("Backend", &backend);
|
engine->rootContext()->setContextProperty("Backend", &backend);
|
||||||
engine->rootContext()->setContextProperty("AppPath", QUrl::fromLocalFile(QDir::currentPath()));
|
|
||||||
#ifdef QT_DEBUG
|
#ifdef QT_DEBUG
|
||||||
bool debugging = true;
|
bool debugging = true;
|
||||||
#else
|
#else
|
||||||
bool debugging = false;
|
bool debugging = false;
|
||||||
#endif
|
#endif
|
||||||
engine->rootContext()->setContextProperty("Debugging", debugging);
|
engine->rootContext()->setContextProperty("Debugging", debugging);
|
||||||
#ifdef Q_OS_ANDROID
|
|
||||||
engine->rootContext()->setContextProperty("Android", true);
|
|
||||||
|
QString system;
|
||||||
|
#if defined(Q_OS_ANDROID)
|
||||||
|
system = "Android";
|
||||||
|
#elif defined(Q_OS_WASM)
|
||||||
|
system = "Web";
|
||||||
|
#elif defined(Q_OS_WIN32)
|
||||||
|
system = "Win";
|
||||||
|
#elif defined(Q_OS_LINUX)
|
||||||
|
system = "Linux";
|
||||||
#else
|
#else
|
||||||
engine->rootContext()->setContextProperty("Android", false);
|
system = "Other";
|
||||||
#endif
|
#endif
|
||||||
|
engine->rootContext()->setContextProperty("OS", system);
|
||||||
|
|
||||||
|
engine->rootContext()->setContextProperty("AppPath", QUrl::fromLocalFile(QDir::currentPath()));
|
||||||
engine->load("qml/main.qml");
|
engine->load("qml/main.qml");
|
||||||
|
|
||||||
if (engine->rootObjects().isEmpty())
|
if (engine->rootObjects().isEmpty())
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
#include "router.h"
|
#include "router.h"
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "client_socket.h"
|
#include "client_socket.h"
|
||||||
|
#ifndef Q_OS_WASM
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
#include "serverplayer.h"
|
#include "serverplayer.h"
|
||||||
|
#endif
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
Router::Router(QObject *parent, ClientSocket *socket, RouterType type)
|
Router::Router(QObject *parent, ClientSocket *socket, RouterType type)
|
||||||
|
@ -13,7 +15,9 @@ Router::Router(QObject *parent, ClientSocket *socket, RouterType type)
|
||||||
setSocket(socket);
|
setSocket(socket);
|
||||||
expectedReplyId = -1;
|
expectedReplyId = -1;
|
||||||
replyTimeout = 0;
|
replyTimeout = 0;
|
||||||
|
#ifndef Q_OS_WASM
|
||||||
extraReplyReadySemaphore = nullptr;
|
extraReplyReadySemaphore = nullptr;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
Router::~Router()
|
Router::~Router()
|
||||||
|
@ -44,14 +48,17 @@ void Router::setSocket(ClientSocket *socket)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef Q_OS_WASM
|
||||||
void Router::setReplyReadySemaphore(QSemaphore *semaphore)
|
void Router::setReplyReadySemaphore(QSemaphore *semaphore)
|
||||||
{
|
{
|
||||||
extraReplyReadySemaphore = semaphore;
|
extraReplyReadySemaphore = semaphore;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void Router::request(int type, const QString& command,
|
void Router::request(int type, const QString& command,
|
||||||
const QString& jsonData, int timeout)
|
const QString& jsonData, int timeout)
|
||||||
{
|
{
|
||||||
|
#ifndef Q_OS_WASM
|
||||||
// In case a request is called without a following waitForReply call
|
// In case a request is called without a following waitForReply call
|
||||||
if (replyReadySemaphore.available() > 0)
|
if (replyReadySemaphore.available() > 0)
|
||||||
replyReadySemaphore.acquire(replyReadySemaphore.available());
|
replyReadySemaphore.acquire(replyReadySemaphore.available());
|
||||||
|
@ -74,6 +81,7 @@ void Router::request(int type, const QString& command,
|
||||||
body << timeout;
|
body << timeout;
|
||||||
|
|
||||||
emit messageReady(QJsonDocument(body).toJson(QJsonDocument::Compact));
|
emit messageReady(QJsonDocument(body).toJson(QJsonDocument::Compact));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Router::reply(int type, const QString& command, const QString& jsonData)
|
void Router::reply(int type, const QString& command, const QString& jsonData)
|
||||||
|
@ -106,6 +114,7 @@ int Router::getTimeout() const
|
||||||
// cancel last request from the sender
|
// cancel last request from the sender
|
||||||
void Router::cancelRequest()
|
void Router::cancelRequest()
|
||||||
{
|
{
|
||||||
|
#ifndef Q_OS_WASM
|
||||||
replyMutex.lock();
|
replyMutex.lock();
|
||||||
expectedReplyId = -1;
|
expectedReplyId = -1;
|
||||||
replyTimeout = 0;
|
replyTimeout = 0;
|
||||||
|
@ -114,22 +123,28 @@ void Router::cancelRequest()
|
||||||
|
|
||||||
if (replyReadySemaphore.available() > 0)
|
if (replyReadySemaphore.available() > 0)
|
||||||
replyReadySemaphore.acquire(replyReadySemaphore.available());
|
replyReadySemaphore.acquire(replyReadySemaphore.available());
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Router::waitForReply()
|
QString Router::waitForReply()
|
||||||
{
|
{
|
||||||
|
#ifndef Q_OS_WASM
|
||||||
replyReadySemaphore.acquire();
|
replyReadySemaphore.acquire();
|
||||||
return m_reply;
|
return m_reply;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Router::waitForReply(int timeout)
|
QString Router::waitForReply(int timeout)
|
||||||
{
|
{
|
||||||
|
#ifndef Q_OS_WASM
|
||||||
replyReadySemaphore.tryAcquire(1, timeout * 1000);
|
replyReadySemaphore.tryAcquire(1, timeout * 1000);
|
||||||
return m_reply;
|
return m_reply;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Router::abortRequest()
|
void Router::abortRequest()
|
||||||
{
|
{
|
||||||
|
#ifndef Q_OS_WASM
|
||||||
replyMutex.lock();
|
replyMutex.lock();
|
||||||
if (expectedReplyId != -1) {
|
if (expectedReplyId != -1) {
|
||||||
replyReadySemaphore.release();
|
replyReadySemaphore.release();
|
||||||
|
@ -139,10 +154,12 @@ void Router::abortRequest()
|
||||||
extraReplyReadySemaphore = nullptr;
|
extraReplyReadySemaphore = nullptr;
|
||||||
}
|
}
|
||||||
replyMutex.unlock();
|
replyMutex.unlock();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Router::handlePacket(const QByteArray& rawPacket)
|
void Router::handlePacket(const QByteArray& rawPacket)
|
||||||
{
|
{
|
||||||
|
#ifndef Q_OS_WASM
|
||||||
static QMap<QString, void (*)(ServerPlayer *, const QString &)> lobby_actions;
|
static QMap<QString, void (*)(ServerPlayer *, const QString &)> lobby_actions;
|
||||||
if (lobby_actions.size() <= 0) {
|
if (lobby_actions.size() <= 0) {
|
||||||
lobby_actions["UpdateAvatar"] = [](ServerPlayer *sender, const QString &jsonData){
|
lobby_actions["UpdateAvatar"] = [](ServerPlayer *sender, const QString &jsonData){
|
||||||
|
@ -260,5 +277,28 @@ void Router::handlePacket(const QByteArray& rawPacket)
|
||||||
locker.unlock();
|
locker.unlock();
|
||||||
emit replyReady();
|
emit replyReady();
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
QJsonDocument packet = QJsonDocument::fromJson(rawPacket);
|
||||||
|
if (packet.isNull() || !packet.isArray())
|
||||||
|
return;
|
||||||
|
|
||||||
|
int requestId = packet[0].toInt();
|
||||||
|
int type = packet[1].toInt();
|
||||||
|
QString command = packet[2].toString();
|
||||||
|
QString jsonData = packet[3].toString();
|
||||||
|
|
||||||
|
if (type & TYPE_NOTIFICATION) {
|
||||||
|
if (type & DEST_CLIENT) {
|
||||||
|
ClientInstance->callLua(command, jsonData);
|
||||||
|
}
|
||||||
|
} else if (type & TYPE_REQUEST) {
|
||||||
|
this->requestId = requestId;
|
||||||
|
this->requestTimeout = packet[4].toInt();
|
||||||
|
|
||||||
|
if (type & DEST_CLIENT) {
|
||||||
|
qobject_cast<Client *>(parent())->callLua(command, jsonData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,9 @@ public:
|
||||||
ClientSocket *getSocket() const;
|
ClientSocket *getSocket() const;
|
||||||
void setSocket(ClientSocket *socket);
|
void setSocket(ClientSocket *socket);
|
||||||
|
|
||||||
|
#ifndef Q_OS_WASM
|
||||||
void setReplyReadySemaphore(QSemaphore *semaphore);
|
void setReplyReadySemaphore(QSemaphore *semaphore);
|
||||||
|
#endif
|
||||||
|
|
||||||
void request(int type, const QString &command,
|
void request(int type, const QString &command,
|
||||||
const QString &jsonData, int timeout);
|
const QString &jsonData, int timeout);
|
||||||
|
@ -66,8 +68,10 @@ private:
|
||||||
int expectedReplyId;
|
int expectedReplyId;
|
||||||
int replyTimeout;
|
int replyTimeout;
|
||||||
QString m_reply; // should be json string
|
QString m_reply; // should be json string
|
||||||
|
#ifndef Q_OS_WASM
|
||||||
QSemaphore replyReadySemaphore;
|
QSemaphore replyReadySemaphore;
|
||||||
QSemaphore *extraReplyReadySemaphore;
|
QSemaphore *extraReplyReadySemaphore;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Two Lua global table for callbacks and interactions
|
// Two Lua global table for callbacks and interactions
|
||||||
// stored in the lua_State of the sender
|
// stored in the lua_State of the sender
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
%module fk
|
||||||
|
|
||||||
|
%{
|
||||||
|
#include "client.h"
|
||||||
|
#include "serverplayer.h"
|
||||||
|
#include "clientplayer.h"
|
||||||
|
#include "room.h"
|
||||||
|
#include "qmlbackend.h"
|
||||||
|
#include "util.h"
|
||||||
|
%}
|
||||||
|
|
||||||
|
%include "naturalvar.i"
|
||||||
|
%include "qt.i"
|
||||||
|
%include "player.i"
|
||||||
|
%include "client.i"
|
|
@ -34,22 +34,3 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
extern ClientPlayer *Self;
|
extern ClientPlayer *Self;
|
||||||
|
|
||||||
%nodefaultctor ServerPlayer;
|
|
||||||
%nodefaultdtor ServerPlayer;
|
|
||||||
class ServerPlayer : public Player {
|
|
||||||
public:
|
|
||||||
Server *getServer() const;
|
|
||||||
Room *getRoom() const;
|
|
||||||
void setRoom(Room *room);
|
|
||||||
|
|
||||||
void speak(const QString &message);
|
|
||||||
|
|
||||||
void doRequest(const QString &command,
|
|
||||||
const QString &json_data, int timeout);
|
|
||||||
QString waitForReply();
|
|
||||||
QString waitForReply(int timeout);
|
|
||||||
void doNotify(const QString &command, const QString &json_data);
|
|
||||||
|
|
||||||
void prepareForRequest(const QString &command, const QString &data);
|
|
||||||
};
|
|
||||||
|
|
|
@ -93,3 +93,21 @@ void Room::roomStart() {
|
||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
%nodefaultctor ServerPlayer;
|
||||||
|
%nodefaultdtor ServerPlayer;
|
||||||
|
class ServerPlayer : public Player {
|
||||||
|
public:
|
||||||
|
Server *getServer() const;
|
||||||
|
Room *getRoom() const;
|
||||||
|
void setRoom(Room *room);
|
||||||
|
|
||||||
|
void speak(const QString &message);
|
||||||
|
|
||||||
|
void doRequest(const QString &command,
|
||||||
|
const QString &json_data, int timeout);
|
||||||
|
QString waitForReply();
|
||||||
|
QString waitForReply(int timeout);
|
||||||
|
void doNotify(const QString &command, const QString &json_data);
|
||||||
|
|
||||||
|
void prepareForRequest(const QString &command, const QString &data);
|
||||||
|
};
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "qmlbackend.h"
|
#include "qmlbackend.h"
|
||||||
|
#ifndef Q_OS_WASM
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
|
#endif
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
@ -11,14 +13,18 @@ QmlBackend::QmlBackend(QObject* parent)
|
||||||
Backend = this;
|
Backend = this;
|
||||||
engine = nullptr;
|
engine = nullptr;
|
||||||
rsa = RSA_new();
|
rsa = RSA_new();
|
||||||
|
#ifndef Q_OS_WASM
|
||||||
parser = fkp_new_parser();
|
parser = fkp_new_parser();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
QmlBackend::~QmlBackend()
|
QmlBackend::~QmlBackend()
|
||||||
{
|
{
|
||||||
Backend = nullptr;
|
Backend = nullptr;
|
||||||
RSA_free(rsa);
|
RSA_free(rsa);
|
||||||
|
#ifndef Q_OS_WASM
|
||||||
fkp_close(parser);
|
fkp_close(parser);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
QQmlApplicationEngine *QmlBackend::getEngine() const
|
QQmlApplicationEngine *QmlBackend::getEngine() const
|
||||||
|
@ -33,6 +39,7 @@ void QmlBackend::setEngine(QQmlApplicationEngine *engine)
|
||||||
|
|
||||||
void QmlBackend::startServer(ushort port)
|
void QmlBackend::startServer(ushort port)
|
||||||
{
|
{
|
||||||
|
#ifndef Q_OS_WASM
|
||||||
if (!ServerInstance) {
|
if (!ServerInstance) {
|
||||||
Server *server = new Server(this);
|
Server *server = new Server(this);
|
||||||
|
|
||||||
|
@ -41,6 +48,7 @@ void QmlBackend::startServer(ushort port)
|
||||||
emit notifyUI("ErrorMsg", tr("Cannot start server!"));
|
emit notifyUI("ErrorMsg", tr("Cannot start server!"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlBackend::joinServer(QString address)
|
void QmlBackend::joinServer(QString address)
|
||||||
|
@ -81,7 +89,7 @@ void QmlBackend::cd(const QString &path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList QmlBackend::ls(const QString &dir) {
|
QStringList QmlBackend::ls(const QString &dir) {
|
||||||
return QDir(dir).entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
|
return QDir(QUrl(dir).path()).entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString QmlBackend::pwd() {
|
QString QmlBackend::pwd() {
|
||||||
|
@ -169,12 +177,14 @@ QString QmlBackend::callLuaFunction(const QString &func_name,
|
||||||
}
|
}
|
||||||
|
|
||||||
QString QmlBackend::pubEncrypt(const QString &key, const QString &data) {
|
QString QmlBackend::pubEncrypt(const QString &key, const QString &data) {
|
||||||
BIO *keyio = BIO_new_mem_buf(key.toLatin1().data(), -1);
|
auto key_bytes = key.toLatin1();
|
||||||
|
BIO *keyio = BIO_new_mem_buf(key_bytes.constData(), -1);
|
||||||
PEM_read_bio_RSAPublicKey(keyio, &rsa, NULL, NULL);
|
PEM_read_bio_RSAPublicKey(keyio, &rsa, NULL, NULL);
|
||||||
BIO_free_all(keyio);
|
BIO_free_all(keyio);
|
||||||
|
|
||||||
|
auto data_bytes = data.toUtf8();
|
||||||
unsigned char buf[RSA_size(rsa)];
|
unsigned char buf[RSA_size(rsa)];
|
||||||
RSA_public_encrypt(data.length(), (const unsigned char *)data.toUtf8().data(),
|
RSA_public_encrypt(data.length(), (const unsigned char *)data_bytes.constData(),
|
||||||
buf, rsa, RSA_PKCS1_PADDING);
|
buf, rsa, RSA_PKCS1_PADDING);
|
||||||
return QByteArray::fromRawData((const char *)buf, RSA_size(rsa)).toBase64();
|
return QByteArray::fromRawData((const char *)buf, RSA_size(rsa)).toBase64();
|
||||||
}
|
}
|
||||||
|
@ -209,6 +219,7 @@ void QmlBackend::saveConf(const QString &conf) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlBackend::parseFkp(const QString &fileName) {
|
void QmlBackend::parseFkp(const QString &fileName) {
|
||||||
|
#ifndef Q_OS_WASM
|
||||||
if (!QFile::exists(fileName)) {
|
if (!QFile::exists(fileName)) {
|
||||||
// errorEdit->setText(tr("File does not exist!"));
|
// errorEdit->setText(tr("File does not exist!"));
|
||||||
return;
|
return;
|
||||||
|
@ -245,8 +256,10 @@ void QmlBackend::parseFkp(const QString &fileName) {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
QDir::setCurrent(cwd);
|
QDir::setCurrent(cwd);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef Q_OS_WASM
|
||||||
static void copyFkpHash2QHash(QHash<QString, QString> &dst, fkp_hash *from) {
|
static void copyFkpHash2QHash(QHash<QString, QString> &dst, fkp_hash *from) {
|
||||||
dst.clear();
|
dst.clear();
|
||||||
for (size_t i = 0; i < from->capacity; i++) {
|
for (size_t i = 0; i < from->capacity; i++) {
|
||||||
|
@ -261,6 +274,7 @@ void QmlBackend::readHashFromParser() {
|
||||||
copyFkpHash2QHash(skills, parser->skills);
|
copyFkpHash2QHash(skills, parser->skills);
|
||||||
copyFkpHash2QHash(marks, parser->marks);
|
copyFkpHash2QHash(marks, parser->marks);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
QString QmlBackend::calcFileMD5() {
|
QString QmlBackend::calcFileMD5() {
|
||||||
return ::calcFileMD5();
|
return ::calcFileMD5();
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
#ifndef _QMLBACKEND_H
|
#ifndef _QMLBACKEND_H
|
||||||
#define _QMLBACKEND_H
|
#define _QMLBACKEND_H
|
||||||
|
|
||||||
|
#ifndef Q_OS_WASM
|
||||||
#include "fkparse.h"
|
#include "fkparse.h"
|
||||||
|
#endif
|
||||||
#include <qtmetamacros.h>
|
#include <qtmetamacros.h>
|
||||||
|
|
||||||
class QmlBackend : public QObject {
|
class QmlBackend : public QObject {
|
||||||
|
@ -48,7 +50,9 @@ signals:
|
||||||
private:
|
private:
|
||||||
QQmlApplicationEngine *engine;
|
QQmlApplicationEngine *engine;
|
||||||
RSA *rsa;
|
RSA *rsa;
|
||||||
|
#ifndef Q_OS_WASM
|
||||||
fkp_parser *parser;
|
fkp_parser *parser;
|
||||||
|
#endif
|
||||||
QHash<QString, QString> generals;
|
QHash<QString, QString> generals;
|
||||||
QHash<QString, QString> skills;
|
QHash<QString, QString> skills;
|
||||||
QHash<QString, QString> marks;
|
QHash<QString, QString> marks;
|
||||||
|
|
Loading…
Reference in New Issue