mirror of
https://github.com/Qsgs-Fans/FreeKill.git
synced 2024-11-16 03:32:34 +08:00
parent
375147afa1
commit
48f3ae3ecd
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -16,6 +16,7 @@ tags
|
||||||
|
|
||||||
# file produced by game
|
# file produced by game
|
||||||
/FreeKill
|
/FreeKill
|
||||||
|
/mymod
|
||||||
FreeKill.exe
|
FreeKill.exe
|
||||||
freekill-wrap.cxx
|
freekill-wrap.cxx
|
||||||
server/users.db
|
server/users.db
|
||||||
|
|
50
Fk/ModMaker/CreateSomething.qml
Normal file
50
Fk/ModMaker/CreateSomething.qml
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: root
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 16
|
||||||
|
signal finished()
|
||||||
|
signal accepted(string result)
|
||||||
|
|
||||||
|
property string head
|
||||||
|
property string hint
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: qsTr(head)
|
||||||
|
font.pixelSize: 20
|
||||||
|
font.bold: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
wrapMode: Text.WrapAnywhere
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: qsTr(hint)
|
||||||
|
Layout.fillWidth: true
|
||||||
|
wrapMode: Text.WrapAnywhere
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: qsTr("validator_hint")
|
||||||
|
Layout.fillWidth: true
|
||||||
|
wrapMode: Text.WrapAnywhere
|
||||||
|
}
|
||||||
|
|
||||||
|
TextField {
|
||||||
|
id: edit
|
||||||
|
font.pixelSize: 18
|
||||||
|
Layout.fillWidth: true
|
||||||
|
validator: RegularExpressionValidator { regularExpression: /[0-9A-Za-z_]+/ }
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: "OK"
|
||||||
|
enabled: edit.text.length >= 4
|
||||||
|
onClicked: {
|
||||||
|
accepted(edit.text);
|
||||||
|
finished();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
36
Fk/ModMaker/ModConfig.qml
Normal file
36
Fk/ModMaker/ModConfig.qml
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
property var conf
|
||||||
|
|
||||||
|
property string userName
|
||||||
|
property string email
|
||||||
|
property var modList: []
|
||||||
|
|
||||||
|
function loadConf() {
|
||||||
|
conf = JSON.parse(ModBackend.readFile("mymod/config.json"));
|
||||||
|
userName = conf.userName ?? "";
|
||||||
|
email = conf.email ?? "";
|
||||||
|
modList = conf.modList ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveConf() {
|
||||||
|
conf.userName = userName;
|
||||||
|
conf.email = email;
|
||||||
|
conf.modList = modList;
|
||||||
|
|
||||||
|
ModBackend.saveToFile("mymod/config.json", JSON.stringify(conf, undefined, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
function addMod(mod) {
|
||||||
|
modList.push(mod);
|
||||||
|
saveConf();
|
||||||
|
modListChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeMod(mod) {
|
||||||
|
modList.splice(modList.indexOf(mod), 1);
|
||||||
|
saveConf();
|
||||||
|
modListChanged();
|
||||||
|
}
|
||||||
|
}
|
113
Fk/ModMaker/ModInit.qml
Normal file
113
Fk/ModMaker/ModInit.qml
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
property bool configOK: modConfig.userName !== "" && modConfig.email !== ""
|
||||||
|
|
||||||
|
ToolBar {
|
||||||
|
id: bar
|
||||||
|
width: parent.width
|
||||||
|
RowLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
ToolButton {
|
||||||
|
icon.source: AppPath + "/image/modmaker/back"
|
||||||
|
onClicked: mainStack.pop();
|
||||||
|
}
|
||||||
|
Label {
|
||||||
|
text: qsTr("ModMaker")
|
||||||
|
horizontalAlignment: Qt.AlignHCenter
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
ToolButton {
|
||||||
|
icon.source: AppPath + "/image/modmaker/menu"
|
||||||
|
onClicked: {
|
||||||
|
dialog.source = "UserInfo.qml";
|
||||||
|
drawer.open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: parent.width
|
||||||
|
height: parent.height - bar.height
|
||||||
|
anchors.top: bar.bottom
|
||||||
|
color: "snow"
|
||||||
|
opacity: 0.75
|
||||||
|
|
||||||
|
Text {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: root.configOK ? "" : qsTr("config is incomplete")
|
||||||
|
}
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
anchors.fill: parent
|
||||||
|
model: modConfig.modList
|
||||||
|
delegate: Text { text: modelData }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RoundButton {
|
||||||
|
visible: root.configOK
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.margins: 40
|
||||||
|
scale: 2
|
||||||
|
icon.source: AppPath + "/image/modmaker/add"
|
||||||
|
onClicked: {
|
||||||
|
dialog.source = "CreateSomething.qml";
|
||||||
|
dialog.item.head = "create_mod";
|
||||||
|
dialog.item.hint = "create_mod_hint";
|
||||||
|
drawer.open();
|
||||||
|
dialog.item.accepted.connect((name) => {
|
||||||
|
createNewMod(name);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Drawer {
|
||||||
|
id: drawer
|
||||||
|
width: parent.width * 0.4 / mainWindow.scale
|
||||||
|
height: parent.height / mainWindow.scale
|
||||||
|
dim: false
|
||||||
|
clip: true
|
||||||
|
dragMargin: 0
|
||||||
|
scale: mainWindow.scale
|
||||||
|
transformOrigin: Item.TopLeft
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: dialog
|
||||||
|
anchors.fill: parent
|
||||||
|
onSourceChanged: {
|
||||||
|
if (item === null)
|
||||||
|
return;
|
||||||
|
item.finished.connect(() => {
|
||||||
|
sourceComponent = undefined;
|
||||||
|
drawer.close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
onSourceComponentChanged: sourceChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createNewMod(name) {
|
||||||
|
const banned = [ "test", "standard", "standard_cards", "maneuvering" ];
|
||||||
|
if (banned.indexOf(name) !== -1 || modConfig.modList.indexOf(name) !== -1) {
|
||||||
|
toast.show(qsTr("cannot use this mod name"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ModBackend.createMod(name);
|
||||||
|
const modInfo = {
|
||||||
|
name: name,
|
||||||
|
descrption: "",
|
||||||
|
author: modConfig.userName,
|
||||||
|
};
|
||||||
|
ModBackend.saveToFile(`mymod/${name}/mod.json`, JSON.stringify(modInfo, undefined, 2));
|
||||||
|
ModBackend.saveToFile(`mymod/${name}/.gitignore`, "init.lua");
|
||||||
|
ModBackend.stageFiles(name);
|
||||||
|
ModBackend.commitChanges(name, "Initial commit", modConfig.userName, modConfig.email);
|
||||||
|
modConfig.addMod(name);
|
||||||
|
}
|
||||||
|
}
|
75
Fk/ModMaker/UserInfo.qml
Normal file
75
Fk/ModMaker/UserInfo.qml
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 16
|
||||||
|
signal finished()
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: qsTr("help_text")
|
||||||
|
Layout.fillWidth: true
|
||||||
|
wrapMode: Text.WrapAnywhere
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors.rightMargin: 8
|
||||||
|
spacing: 16
|
||||||
|
Text {
|
||||||
|
text: qsTr("username")
|
||||||
|
}
|
||||||
|
TextField {
|
||||||
|
id: userName
|
||||||
|
font.pixelSize: 18
|
||||||
|
text: modConfig.userName
|
||||||
|
Layout.fillWidth: true
|
||||||
|
onTextChanged: {
|
||||||
|
modConfig.userName = text;
|
||||||
|
modConfig.saveConf();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors.rightMargin: 8
|
||||||
|
spacing: 16
|
||||||
|
Text {
|
||||||
|
text: qsTr("email")
|
||||||
|
}
|
||||||
|
TextField {
|
||||||
|
id: emailAddr
|
||||||
|
font.pixelSize: 18
|
||||||
|
Layout.fillWidth: true
|
||||||
|
text: modConfig.email
|
||||||
|
onTextChanged: {
|
||||||
|
modConfig.email = text;
|
||||||
|
modConfig.saveConf();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: qsTr("key_help_text")
|
||||||
|
Layout.fillWidth: true
|
||||||
|
wrapMode: Text.WrapAnywhere
|
||||||
|
textFormat: Text.RichText
|
||||||
|
onLinkActivated: Qt.openUrlExternally(link);
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: qsTr("copy pubkey")
|
||||||
|
Layout.fillWidth: true
|
||||||
|
onClicked: {
|
||||||
|
const key = "mymod/id_rsa.pub";
|
||||||
|
if (!Backend.exists(key)) {
|
||||||
|
ModBackend.initKey();
|
||||||
|
}
|
||||||
|
const pubkey = ModBackend.readFile(key);
|
||||||
|
Backend.copyToClipboard(pubkey);
|
||||||
|
toast.show(qsTr("pubkey copied"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
55
Fk/ModMaker/main.qml
Normal file
55
Fk/ModMaker/main.qml
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Component { id: modInit; ModInit {} }
|
||||||
|
|
||||||
|
StackView {
|
||||||
|
id: modStack
|
||||||
|
anchors.fill: parent
|
||||||
|
pushEnter: Transition {
|
||||||
|
PropertyAnimation {
|
||||||
|
property: "opacity"
|
||||||
|
from: 0
|
||||||
|
to:1
|
||||||
|
duration: 200
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pushExit: Transition {
|
||||||
|
PropertyAnimation {
|
||||||
|
property: "opacity"
|
||||||
|
from: 1
|
||||||
|
to:0
|
||||||
|
duration: 200
|
||||||
|
}
|
||||||
|
}
|
||||||
|
popEnter: Transition {
|
||||||
|
PropertyAnimation {
|
||||||
|
property: "opacity"
|
||||||
|
from: 0
|
||||||
|
to:1
|
||||||
|
duration: 200
|
||||||
|
}
|
||||||
|
}
|
||||||
|
popExit: Transition {
|
||||||
|
PropertyAnimation {
|
||||||
|
property: "opacity"
|
||||||
|
from: 1
|
||||||
|
to:0
|
||||||
|
duration: 200
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ModConfig {
|
||||||
|
id: modConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
if (!ModBackend) {
|
||||||
|
Backend.createModBackend();
|
||||||
|
}
|
||||||
|
modConfig.loadConf();
|
||||||
|
modStack.push(modInit);
|
||||||
|
}
|
||||||
|
}
|
2
Fk/ModMaker/qmldir
Normal file
2
Fk/ModMaker/qmldir
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
module Fk.ModMaker
|
||||||
|
ModMaker 1.0 main.qml
|
|
@ -54,6 +54,7 @@ Item {
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
textFormat: Text.MarkdownText
|
textFormat: Text.MarkdownText
|
||||||
font.pixelSize: 18
|
font.pixelSize: 18
|
||||||
|
onLinkActivated: Qt.openUrlExternally(link);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -183,6 +183,16 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Temp
|
||||||
|
Button {
|
||||||
|
text: qsTr("Mod Making")
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
onClicked: {
|
||||||
|
mainStack.push(modMaker);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function downloadComplete() {
|
function downloadComplete() {
|
||||||
toast.show(qsTr("updated packages for md5"));
|
toast.show(qsTr("updated packages for md5"));
|
||||||
}
|
}
|
||||||
|
|
3
Fk/Pages/ModMaker.qml
Normal file
3
Fk/Pages/ModMaker.qml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
import Fk.ModMaker as Md
|
||||||
|
|
||||||
|
Md.ModMaker {}
|
|
@ -10,3 +10,4 @@ ModesOverview 1.0 ModesOverview.qml
|
||||||
PackageManage 1.0 PackageManage.qml
|
PackageManage 1.0 PackageManage.qml
|
||||||
Room 1.0 Room.qml
|
Room 1.0 Room.qml
|
||||||
TileButton 1.0 TileButton.qml
|
TileButton 1.0 TileButton.qml
|
||||||
|
ModMaker 1.0 ModMaker.qml
|
||||||
|
|
|
@ -51,6 +51,7 @@ Item {
|
||||||
|
|
||||||
Component { id: init; Init {} }
|
Component { id: init; Init {} }
|
||||||
Component { id: packageManage; PackageManage {} }
|
Component { id: packageManage; PackageManage {} }
|
||||||
|
Component { id: modMaker; ModMaker {} }
|
||||||
Component { id: lobby; Lobby {} }
|
Component { id: lobby; Lobby {} }
|
||||||
Component { id: generalsOverview; GeneralsOverview {} }
|
Component { id: generalsOverview; GeneralsOverview {} }
|
||||||
Component { id: cardsOverview; CardsOverview {} }
|
Component { id: cardsOverview; CardsOverview {} }
|
||||||
|
|
BIN
image/modmaker/add.png
Normal file
BIN
image/modmaker/add.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 330 B |
BIN
image/modmaker/back.png
Normal file
BIN
image/modmaker/back.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 358 B |
BIN
image/modmaker/menu.png
Normal file
BIN
image/modmaker/menu.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 351 B |
BIN
image/modmaker/ok.png
Normal file
BIN
image/modmaker/ok.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 414 B |
|
@ -79,6 +79,10 @@
|
||||||
<source>PackageManage</source>
|
<source>PackageManage</source>
|
||||||
<translation>管理拓展包</translation>
|
<translation>管理拓展包</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Mod Making</source>
|
||||||
|
<translation>制作Mod</translation>
|
||||||
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Welcome back!</source>
|
<source>Welcome back!</source>
|
||||||
<translation>欢迎回来!</translation>
|
<translation>欢迎回来!</translation>
|
||||||
|
@ -212,4 +216,67 @@
|
||||||
<translation>已复制。</translation>
|
<translation>已复制。</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
|
||||||
|
<context>
|
||||||
|
<name>ModInit</name>
|
||||||
|
<message>
|
||||||
|
<source>ModMaker</source>
|
||||||
|
<translation>新月杀Mod制作器 - 首页</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>config is incomplete</source>
|
||||||
|
<translation>
|
||||||
|
Mod制作器还未正确配置!
|
||||||
|
请点击右上角配置好用户名和邮箱</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>cannot use this mod name</source>
|
||||||
|
<translation>不能给mod取这个名字</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context>
|
||||||
|
<name>UserInfo</name>
|
||||||
|
<message>
|
||||||
|
<source>help_text</source>
|
||||||
|
<translation>用户名和邮箱需要填入和git服务器上相同的名字和邮箱。</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>username</source>
|
||||||
|
<translation>用户名</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>email</source>
|
||||||
|
<translation>邮箱</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>key_help_text</source>
|
||||||
|
<translation>公钥是你向git服务器证明身份的手段。请点击按钮复制公钥,然后在网页中添加SSH密钥。详见新月杀Mod制作器教程。</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>copy pubkey</source>
|
||||||
|
<translation>复制公钥</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>pubkey copied</source>
|
||||||
|
<translation>公钥已经复制到剪贴板。</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
|
||||||
|
<context>
|
||||||
|
<name>CreateSomething</name>
|
||||||
|
<message>
|
||||||
|
<source>validator_hint</source>
|
||||||
|
<translation>注意:你仅可以输入大小写字母、数字和下划线,且长度至少为4。这里输入的只是内部名称,它的中文名你可以稍后指定。</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>create_mod</source>
|
||||||
|
<translation>新建Mod</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>create_mod_hint</source>
|
||||||
|
<translation>请输入mod的名称。</translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
|
|
||||||
</TS>
|
</TS>
|
||||||
|
|
|
@ -86,13 +86,13 @@ function Card:initialize(name, suit, number, color)
|
||||||
self.color = Card.NoColor
|
self.color = Card.NoColor
|
||||||
end
|
end
|
||||||
|
|
||||||
self.package = nil
|
-- self.package = nil
|
||||||
self.id = 0
|
self.id = 0
|
||||||
self.type = 0
|
self.type = 0
|
||||||
self.sub_type = Card.SubTypeNone
|
self.sub_type = Card.SubTypeNone
|
||||||
self.skill = nil
|
-- self.skill = nil
|
||||||
self.subcards = {}
|
self.subcards = {}
|
||||||
self.skillName = nil -- ""
|
-- self.skillName = nil
|
||||||
self._skillName = ""
|
self._skillName = ""
|
||||||
self.skillNames = {}
|
self.skillNames = {}
|
||||||
self.mark = {}
|
self.mark = {}
|
||||||
|
@ -101,31 +101,21 @@ function Card:initialize(name, suit, number, color)
|
||||||
self.name = string.sub(name, 2, #name)
|
self.name = string.sub(name, 2, #name)
|
||||||
self.is_derived = true
|
self.is_derived = true
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local mt = table.simpleClone(getmetatable(self))
|
function Card:__index(k)
|
||||||
local newidx = mt.__newindex or rawset
|
if k == "skillName" then
|
||||||
mt.__newindex = function(t, k, v)
|
return self._skillName
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Card:__newindex(k, v)
|
||||||
if k == "skillName" then
|
if k == "skillName" then
|
||||||
table.insertIfNeed(self.skillNames, v)
|
table.insertIfNeed(self.skillNames, v)
|
||||||
t._skillName = v
|
self._skillName = v
|
||||||
else
|
else
|
||||||
return newidx(t, k, v)
|
rawset(self, k, v)
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
local idx = mt.__index or rawget
|
|
||||||
mt.__index = function(t, k)
|
|
||||||
if k == "skillName" then
|
|
||||||
return t._skillName
|
|
||||||
end
|
|
||||||
if type(idx) == "table" then
|
|
||||||
return idx[k]
|
|
||||||
end
|
|
||||||
if type(idx) == "function" then
|
|
||||||
return idx(t, k)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
setmetatable(self, mt)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function Card:__tostring()
|
function Card:__tostring()
|
||||||
|
|
|
@ -90,6 +90,7 @@ request_handlers["luckcard"] = function(room, id, reqlist)
|
||||||
local p = room:getPlayerById(id)
|
local p = room:getPlayerById(id)
|
||||||
local cancel = reqlist[3] == "false"
|
local cancel = reqlist[3] == "false"
|
||||||
local luck_data = room:getTag("LuckCardData")
|
local luck_data = room:getTag("LuckCardData")
|
||||||
|
if not (p and luck_data) then return end
|
||||||
local pdata = luck_data[id]
|
local pdata = luck_data[id]
|
||||||
|
|
||||||
if not cancel then
|
if not cancel then
|
||||||
|
|
|
@ -243,7 +243,11 @@ function ServerPlayer:marshal(player)
|
||||||
room:notifyMoveCards({ player }, card_moves)
|
room:notifyMoveCards({ player }, card_moves)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- TODO: pile, mark
|
-- TODO: pile
|
||||||
|
|
||||||
|
for k, v in pairs(self.mark) do
|
||||||
|
player:doNotify("SetPlayerMark", json.encode{self.id, k, v})
|
||||||
|
end
|
||||||
|
|
||||||
for _, s in ipairs(self.player_skills) do
|
for _, s in ipairs(self.player_skills) do
|
||||||
player:doNotify("AddSkill", json.encode{self.id, s.name})
|
player:doNotify("AddSkill", json.encode{self.id, s.name})
|
||||||
|
|
|
@ -1043,7 +1043,7 @@ local wushuang = fk.CreateTriggerSkill{
|
||||||
end
|
end
|
||||||
|
|
||||||
if event == fk.TargetSpecified then
|
if event == fk.TargetSpecified then
|
||||||
return target == player and table.contains({ "slash", "duel" }, data.card.name)
|
return target == player and table.contains({ "slash", "duel" }, data.card.trueName)
|
||||||
else
|
else
|
||||||
return data.to == player.id and data.card.name == "duel"
|
return data.to == player.id and data.card.name == "duel"
|
||||||
end
|
end
|
||||||
|
|
|
@ -19,6 +19,7 @@ if (NOT DEFINED FK_SERVER_ONLY)
|
||||||
list(APPEND freekill_SRCS
|
list(APPEND freekill_SRCS
|
||||||
"client/client.cpp"
|
"client/client.cpp"
|
||||||
"client/clientplayer.cpp"
|
"client/clientplayer.cpp"
|
||||||
|
"ui/mod.cpp"
|
||||||
)
|
)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
|
|
@ -139,33 +139,6 @@ void ExecSQL(sqlite3 *db, const QString &sql) {
|
||||||
|
|
||||||
void CloseDatabase(sqlite3 *db) { sqlite3_close(db); }
|
void CloseDatabase(sqlite3 *db) { sqlite3_close(db); }
|
||||||
|
|
||||||
#ifndef Q_OS_WASM
|
|
||||||
RSA *InitServerRSA() {
|
|
||||||
RSA *rsa = RSA_new();
|
|
||||||
if (!QFile::exists("server/rsa_pub")) {
|
|
||||||
BIGNUM *bne = BN_new();
|
|
||||||
BN_set_word(bne, RSA_F4);
|
|
||||||
RSA_generate_key_ex(rsa, 2048, bne, NULL);
|
|
||||||
|
|
||||||
BIO *bp_pub = BIO_new_file("server/rsa_pub", "w+");
|
|
||||||
PEM_write_bio_RSAPublicKey(bp_pub, rsa);
|
|
||||||
BIO *bp_pri = BIO_new_file("server/rsa", "w+");
|
|
||||||
PEM_write_bio_RSAPrivateKey(bp_pri, rsa, NULL, NULL, 0, NULL, NULL);
|
|
||||||
|
|
||||||
BIO_free_all(bp_pub);
|
|
||||||
BIO_free_all(bp_pri);
|
|
||||||
BN_free(bne);
|
|
||||||
}
|
|
||||||
FILE *keyFile = fopen("server/rsa_pub", "r");
|
|
||||||
PEM_read_RSAPublicKey(keyFile, &rsa, NULL, NULL);
|
|
||||||
fclose(keyFile);
|
|
||||||
keyFile = fopen("server/rsa", "r");
|
|
||||||
PEM_read_RSAPrivateKey(keyFile, &rsa, NULL, NULL);
|
|
||||||
fclose(keyFile);
|
|
||||||
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);
|
||||||
if (!f.open(QIODevice::ReadOnly)) {
|
if (!f.open(QIODevice::ReadOnly)) {
|
||||||
|
@ -173,6 +146,7 @@ static void writeFileMD5(QFile &dest, const QString &fname) {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto data = f.readAll();
|
auto data = f.readAll();
|
||||||
|
f.close();
|
||||||
data.replace(QByteArray("\r\n"), QByteArray("\n"));
|
data.replace(QByteArray("\r\n"), QByteArray("\n"));
|
||||||
auto hash = QCryptographicHash::hash(data, QCryptographicHash::Md5).toHex();
|
auto hash = QCryptographicHash::hash(data, QCryptographicHash::Md5).toHex();
|
||||||
dest.write(fname.toUtf8() + '=' + hash + ';');
|
dest.write(fname.toUtf8() + '=' + hash + ';');
|
||||||
|
|
|
@ -16,10 +16,6 @@ QString SelectFromDb(sqlite3 *db, const QString &sql);
|
||||||
void ExecSQL(sqlite3 *db, const QString &sql);
|
void ExecSQL(sqlite3 *db, const QString &sql);
|
||||||
void CloseDatabase(sqlite3 *db);
|
void CloseDatabase(sqlite3 *db);
|
||||||
|
|
||||||
#ifndef Q_OS_WASM
|
|
||||||
RSA *InitServerRSA();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QString calcFileMD5();
|
QString calcFileMD5();
|
||||||
QByteArray JsonArray2Bytes(const QJsonArray &arr);
|
QByteArray JsonArray2Bytes(const QJsonArray &arr);
|
||||||
QJsonDocument String2Json(const QString &str);
|
QJsonDocument String2Json(const QString &str);
|
||||||
|
|
|
@ -260,6 +260,7 @@ int main(int argc, char *argv[]) {
|
||||||
// 向 Qml 中先定义几个全局变量
|
// 向 Qml 中先定义几个全局变量
|
||||||
engine->rootContext()->setContextProperty("FkVersion", FK_VERSION);
|
engine->rootContext()->setContextProperty("FkVersion", FK_VERSION);
|
||||||
engine->rootContext()->setContextProperty("Backend", &backend);
|
engine->rootContext()->setContextProperty("Backend", &backend);
|
||||||
|
engine->rootContext()->setContextProperty("ModBackend", nullptr);
|
||||||
engine->rootContext()->setContextProperty("Pacman", Pacman);
|
engine->rootContext()->setContextProperty("Pacman", Pacman);
|
||||||
|
|
||||||
#ifdef QT_DEBUG
|
#ifdef QT_DEBUG
|
||||||
|
|
|
@ -14,9 +14,7 @@
|
||||||
typedef int LuaFunction;
|
typedef int LuaFunction;
|
||||||
#include "lua.hpp"
|
#include "lua.hpp"
|
||||||
#include "sqlite3.h"
|
#include "sqlite3.h"
|
||||||
|
#define OPENSSL_API_COMPAT 0x10101000L
|
||||||
#include <openssl/rsa.h>
|
|
||||||
#include <openssl/pem.h>
|
|
||||||
|
|
||||||
#if !defined (Q_OS_ANDROID) && !defined (Q_OS_WASM)
|
#if !defined (Q_OS_ANDROID) && !defined (Q_OS_WASM)
|
||||||
#define DESKTOP_BUILD
|
#define DESKTOP_BUILD
|
||||||
|
|
|
@ -22,7 +22,7 @@ Server *ServerInstance;
|
||||||
Server::Server(QObject *parent) : QObject(parent) {
|
Server::Server(QObject *parent) : QObject(parent) {
|
||||||
ServerInstance = this;
|
ServerInstance = this;
|
||||||
db = OpenDatabase();
|
db = OpenDatabase();
|
||||||
rsa = InitServerRSA();
|
rsa = initServerRSA();
|
||||||
QFile file("server/rsa_pub");
|
QFile file("server/rsa_pub");
|
||||||
file.open(QIODevice::ReadOnly);
|
file.open(QIODevice::ReadOnly);
|
||||||
QTextStream in(&file);
|
QTextStream in(&file);
|
||||||
|
@ -431,6 +431,32 @@ void Server::onUserDisconnected() {
|
||||||
|
|
||||||
void Server::onUserStateChanged() {}
|
void Server::onUserStateChanged() {}
|
||||||
|
|
||||||
|
RSA *Server::initServerRSA() {
|
||||||
|
RSA *rsa = RSA_new();
|
||||||
|
if (!QFile::exists("server/rsa_pub")) {
|
||||||
|
BIGNUM *bne = BN_new();
|
||||||
|
BN_set_word(bne, RSA_F4);
|
||||||
|
RSA_generate_key_ex(rsa, 2048, bne, NULL);
|
||||||
|
|
||||||
|
BIO *bp_pub = BIO_new_file("server/rsa_pub", "w+");
|
||||||
|
PEM_write_bio_RSAPublicKey(bp_pub, rsa);
|
||||||
|
BIO *bp_pri = BIO_new_file("server/rsa", "w+");
|
||||||
|
PEM_write_bio_RSAPrivateKey(bp_pri, rsa, NULL, NULL, 0, NULL, NULL);
|
||||||
|
|
||||||
|
BIO_free_all(bp_pub);
|
||||||
|
BIO_free_all(bp_pri);
|
||||||
|
QFile("server/rsa").setPermissions(QFileDevice::ReadOwner | QFileDevice::WriteOwner);
|
||||||
|
BN_free(bne);
|
||||||
|
}
|
||||||
|
FILE *keyFile = fopen("server/rsa_pub", "r");
|
||||||
|
PEM_read_RSAPublicKey(keyFile, &rsa, NULL, NULL);
|
||||||
|
fclose(keyFile);
|
||||||
|
keyFile = fopen("server/rsa", "r");
|
||||||
|
PEM_read_RSAPrivateKey(keyFile, &rsa, NULL, NULL);
|
||||||
|
fclose(keyFile);
|
||||||
|
return rsa;
|
||||||
|
}
|
||||||
|
|
||||||
void Server::readConfig() {
|
void Server::readConfig() {
|
||||||
QFile file("freekill.server.config.json");
|
QFile file("freekill.server.config.json");
|
||||||
if (!file.open(QIODevice::ReadOnly)) {
|
if (!file.open(QIODevice::ReadOnly)) {
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
#ifndef _SERVER_H
|
#ifndef _SERVER_H
|
||||||
#define _SERVER_H
|
#define _SERVER_H
|
||||||
|
|
||||||
|
#include <openssl/rsa.h>
|
||||||
|
#include <openssl/pem.h>
|
||||||
|
|
||||||
#include <qjsonobject.h>
|
#include <qjsonobject.h>
|
||||||
#include <qjsonvalue.h>
|
#include <qjsonvalue.h>
|
||||||
class ServerSocket;
|
class ServerSocket;
|
||||||
|
@ -67,6 +70,8 @@ private:
|
||||||
sqlite3 *db;
|
sqlite3 *db;
|
||||||
QString md5;
|
QString md5;
|
||||||
|
|
||||||
|
static RSA *initServerRSA();
|
||||||
|
|
||||||
QJsonObject config;
|
QJsonObject config;
|
||||||
void readConfig();
|
void readConfig();
|
||||||
|
|
||||||
|
|
230
src/ui/mod.cpp
Normal file
230
src/ui/mod.cpp
Normal file
|
@ -0,0 +1,230 @@
|
||||||
|
#include "mod.h"
|
||||||
|
#include "git2.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include <openssl/rsa.h>
|
||||||
|
#include <openssl/bn.h>
|
||||||
|
#include <openssl/pem.h>
|
||||||
|
#include <qfiledevice.h>
|
||||||
|
|
||||||
|
ModMaker::ModMaker(QObject *parent) : QObject(parent) {
|
||||||
|
git_libgit2_init();
|
||||||
|
#ifdef Q_OS_ANDROID
|
||||||
|
git_libgit2_opts(GIT_OPT_SET_SSL_CERT_LOCATIONS, NULL, "./certs");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!QDir("mymod").exists()) {
|
||||||
|
QDir(".").mkdir("mymod");
|
||||||
|
}
|
||||||
|
|
||||||
|
db = OpenDatabase("mymod/packages.db", "packages/mymod.sql");
|
||||||
|
}
|
||||||
|
|
||||||
|
ModMaker::~ModMaker() {
|
||||||
|
// git_libgit2_shutdown();
|
||||||
|
sqlite3_close(db);
|
||||||
|
}
|
||||||
|
|
||||||
|
// copied from https://stackoverflow.com/questions/1011572/convert-pem-key-to-ssh-rsa-format
|
||||||
|
static unsigned char pSshHeader[11] = { 0x00, 0x00, 0x00, 0x07, 0x73, 0x73, 0x68, 0x2D, 0x72, 0x73, 0x61};
|
||||||
|
|
||||||
|
static int SshEncodeBuffer(unsigned char *pEncoding, int bufferLen, unsigned char* pBuffer) {
|
||||||
|
int adjustedLen = bufferLen, index;
|
||||||
|
if (*pBuffer & 0x80) {
|
||||||
|
adjustedLen++;
|
||||||
|
pEncoding[4] = 0;
|
||||||
|
index = 5;
|
||||||
|
} else {
|
||||||
|
index = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
pEncoding[0] = (unsigned char) (adjustedLen >> 24);
|
||||||
|
pEncoding[1] = (unsigned char) (adjustedLen >> 16);
|
||||||
|
pEncoding[2] = (unsigned char) (adjustedLen >> 8);
|
||||||
|
pEncoding[3] = (unsigned char) (adjustedLen );
|
||||||
|
memcpy(&pEncoding[index], pBuffer, bufferLen);
|
||||||
|
return index + bufferLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void initSSHKeyPair() {
|
||||||
|
if (!QFile::exists("mymod/id_rsa.pub")) {
|
||||||
|
RSA *rsa = RSA_new();
|
||||||
|
BIGNUM *bne = BN_new();
|
||||||
|
BN_set_word(bne, RSA_F4);
|
||||||
|
RSA_generate_key_ex(rsa, 3072, bne, NULL);
|
||||||
|
|
||||||
|
BIO *bp_pri = BIO_new_file("mymod/id_rsa", "w");
|
||||||
|
PEM_write_bio_RSAPrivateKey(bp_pri, rsa, NULL, NULL, 0, NULL, NULL);
|
||||||
|
BIO_free_all(bp_pri);
|
||||||
|
QFile("mymod/id_rsa").setPermissions(QFileDevice::ReadOwner | QFileDevice::WriteOwner);
|
||||||
|
|
||||||
|
auto n = RSA_get0_n(rsa);
|
||||||
|
auto e = RSA_get0_e(rsa);
|
||||||
|
auto nLen = BN_num_bytes(n);
|
||||||
|
auto eLen = BN_num_bytes(e);
|
||||||
|
auto nBytes = (unsigned char *)malloc(nLen);
|
||||||
|
auto eBytes = (unsigned char *)malloc(eLen);
|
||||||
|
BN_bn2bin(n, nBytes);
|
||||||
|
BN_bn2bin(e, eBytes);
|
||||||
|
|
||||||
|
auto encodingLength = 11 + 4 + eLen + 4 + nLen;
|
||||||
|
// correct depending on the MSB of e and N
|
||||||
|
if (eBytes[0] & 0x80)
|
||||||
|
encodingLength++;
|
||||||
|
if (nBytes[0] & 0x80)
|
||||||
|
encodingLength++;
|
||||||
|
|
||||||
|
auto pEncoding = (unsigned char *)malloc(encodingLength);
|
||||||
|
memcpy(pEncoding, pSshHeader, 11);
|
||||||
|
int index = 0;
|
||||||
|
index = SshEncodeBuffer(&pEncoding[11], eLen, eBytes);
|
||||||
|
index = SshEncodeBuffer(&pEncoding[11 + index], nLen, nBytes);
|
||||||
|
|
||||||
|
auto b64 = BIO_new(BIO_f_base64());
|
||||||
|
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
|
||||||
|
auto bio = BIO_new_file("mymod/id_rsa.pub", "w");
|
||||||
|
BIO_printf(bio, "ssh-rsa ");
|
||||||
|
bio = BIO_push(b64, bio);
|
||||||
|
BIO_write(bio, pEncoding, encodingLength);
|
||||||
|
BIO_flush(bio);
|
||||||
|
bio = BIO_pop(b64);
|
||||||
|
BIO_printf(bio, " FreeKill\n");
|
||||||
|
BIO_flush(bio);
|
||||||
|
|
||||||
|
BIO_free_all(bio);
|
||||||
|
BIO_free_all(b64);
|
||||||
|
BN_free(bne);
|
||||||
|
RSA_free(rsa);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModMaker::initKey() { initSSHKeyPair(); }
|
||||||
|
|
||||||
|
QString ModMaker::readFile(const QString &fileName) {
|
||||||
|
QFile conf(fileName);
|
||||||
|
if (!conf.exists()) {
|
||||||
|
conf.open(QIODevice::WriteOnly);
|
||||||
|
static const char *init_conf = "{}";
|
||||||
|
conf.write(init_conf);
|
||||||
|
conf.close();
|
||||||
|
return init_conf;
|
||||||
|
}
|
||||||
|
conf.open(QIODevice::ReadOnly);
|
||||||
|
QString ret = conf.readAll();
|
||||||
|
conf.close();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModMaker::saveToFile(const QString &fName, const QString &content) {
|
||||||
|
QFile c(fName);
|
||||||
|
c.open(QIODevice::WriteOnly);
|
||||||
|
c.write(content.toUtf8());
|
||||||
|
c.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModMaker::createMod(const QString &name) {
|
||||||
|
init(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModMaker::commitChanges(const QString &name, const QString &msg,
|
||||||
|
const QString &user, const QString &email)
|
||||||
|
{
|
||||||
|
auto userBytes = user.toUtf8();
|
||||||
|
auto emailBytes = email.toUtf8();
|
||||||
|
commit(name, msg, userBytes, emailBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define GIT_FAIL \
|
||||||
|
const git_error *e = git_error_last(); \
|
||||||
|
qCritical("Error %d/%d: %s\n", error, e->klass, e->message)
|
||||||
|
|
||||||
|
#define GIT_CHK(s) do { \
|
||||||
|
error = (s); \
|
||||||
|
if (error < 0) { \
|
||||||
|
GIT_FAIL; \
|
||||||
|
goto clean; \
|
||||||
|
}} while (0)
|
||||||
|
|
||||||
|
static int fk_cred_cb(git_cred **out, const char *url, const char *name,
|
||||||
|
unsigned int allowed_types, void *payload)
|
||||||
|
{
|
||||||
|
initSSHKeyPair();
|
||||||
|
return git_cred_ssh_key_new(out, "git", "mymod/id_rsa.pub", "mymod/id_rsa", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
int ModMaker::init(const QString &pkg) {
|
||||||
|
QString path = "mymod/" + pkg;
|
||||||
|
int error;
|
||||||
|
git_repository *repo = NULL;
|
||||||
|
git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
|
||||||
|
opts.flags |= GIT_REPOSITORY_INIT_MKPATH; /* mkdir as needed to create repo */
|
||||||
|
error = git_repository_init_ext(&repo, path.toLatin1().constData(), &opts);
|
||||||
|
if (error < 0) {
|
||||||
|
GIT_FAIL;
|
||||||
|
}
|
||||||
|
git_repository_free(repo);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ModMaker::add(const QString &pkg) {
|
||||||
|
QString path = "mymod/" + pkg;
|
||||||
|
int error;
|
||||||
|
git_repository *repo = NULL;
|
||||||
|
git_index *index = NULL;
|
||||||
|
|
||||||
|
GIT_CHK(git_repository_open(&repo, path.toLatin1()));
|
||||||
|
GIT_CHK(git_repository_index(&index, repo));
|
||||||
|
GIT_CHK(git_index_add_all(index, NULL, GIT_INDEX_ADD_DEFAULT, NULL, NULL));
|
||||||
|
GIT_CHK(git_index_write(index));
|
||||||
|
|
||||||
|
clean:
|
||||||
|
git_repository_free(repo);
|
||||||
|
git_index_free(index);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ModMaker::commit(const QString &pkg, const QString &msg, const char *user, const char *email) {
|
||||||
|
QString path = "mymod/" + pkg;
|
||||||
|
int error;
|
||||||
|
git_repository *repo = NULL;
|
||||||
|
git_oid commit_oid,tree_oid;
|
||||||
|
git_tree *tree;
|
||||||
|
git_index *index;
|
||||||
|
git_object *parent = NULL;
|
||||||
|
git_reference *ref = NULL;
|
||||||
|
git_signature *signature;
|
||||||
|
|
||||||
|
GIT_CHK(git_repository_open(&repo, path.toLatin1()));
|
||||||
|
error = git_revparse_ext(&parent, &ref, repo, "HEAD");
|
||||||
|
if (error == GIT_ENOTFOUND) {
|
||||||
|
// printf("HEAD not found. Creating first commit\n");
|
||||||
|
error = 0;
|
||||||
|
} else if (error != 0) {
|
||||||
|
GIT_FAIL;
|
||||||
|
goto clean;
|
||||||
|
}
|
||||||
|
|
||||||
|
GIT_CHK(git_repository_index(&index, repo));
|
||||||
|
GIT_CHK(git_index_write_tree(&tree_oid, index));
|
||||||
|
GIT_CHK(git_index_write(index));
|
||||||
|
GIT_CHK(git_tree_lookup(&tree, repo, &tree_oid));
|
||||||
|
GIT_CHK(git_signature_now(&signature, user, email));
|
||||||
|
GIT_CHK(git_commit_create_v(
|
||||||
|
&commit_oid,
|
||||||
|
repo,
|
||||||
|
"HEAD",
|
||||||
|
signature,
|
||||||
|
signature,
|
||||||
|
NULL,
|
||||||
|
msg.toUtf8(),
|
||||||
|
tree,
|
||||||
|
parent ? 1 : 0, parent));
|
||||||
|
|
||||||
|
clean:
|
||||||
|
git_repository_free(repo);
|
||||||
|
git_index_free(index);
|
||||||
|
git_signature_free(signature);
|
||||||
|
git_tree_free(tree);
|
||||||
|
git_object_free(parent);
|
||||||
|
git_reference_free(ref);
|
||||||
|
return error;
|
||||||
|
}
|
32
src/ui/mod.h
Normal file
32
src/ui/mod.h
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#ifndef _DIY_H
|
||||||
|
#define _DIY_H
|
||||||
|
|
||||||
|
#include <qtmetamacros.h>
|
||||||
|
class ModMaker : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
ModMaker(QObject *parent = nullptr);
|
||||||
|
~ModMaker();
|
||||||
|
|
||||||
|
Q_INVOKABLE void initKey();
|
||||||
|
|
||||||
|
Q_INVOKABLE QString readFile(const QString &fileName);
|
||||||
|
Q_INVOKABLE void saveToFile(const QString &fileName, const QString &content);
|
||||||
|
|
||||||
|
Q_INVOKABLE void createMod(const QString &name);
|
||||||
|
Q_INVOKABLE void stageFiles(const QString &name) { add(name); }
|
||||||
|
Q_INVOKABLE void commitChanges(const QString &name, const QString &msg,
|
||||||
|
const QString &user, const QString &email);
|
||||||
|
|
||||||
|
private:
|
||||||
|
sqlite3 *db;
|
||||||
|
|
||||||
|
// git functions
|
||||||
|
int init(const QString &pkg);
|
||||||
|
int add(const QString &pkg);
|
||||||
|
int commit(const QString &pkg, const QString &msg, const char *user, const char *email);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include <QClipboard>
|
#include <QClipboard>
|
||||||
#include <QMediaPlayer>
|
#include <QMediaPlayer>
|
||||||
|
#include "mod.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
@ -227,10 +228,13 @@ QString QmlBackend::loadConf() {
|
||||||
conf.open(QIODevice::WriteOnly);
|
conf.open(QIODevice::WriteOnly);
|
||||||
static const char *init_conf = "{}";
|
static const char *init_conf = "{}";
|
||||||
conf.write(init_conf);
|
conf.write(init_conf);
|
||||||
|
conf.close();
|
||||||
return init_conf;
|
return init_conf;
|
||||||
}
|
}
|
||||||
conf.open(QIODevice::ReadOnly);
|
conf.open(QIODevice::ReadOnly);
|
||||||
return conf.readAll();
|
auto ret = conf.readAll();
|
||||||
|
conf.close();
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString QmlBackend::loadTips() {
|
QString QmlBackend::loadTips() {
|
||||||
|
@ -239,16 +243,20 @@ QString QmlBackend::loadTips() {
|
||||||
conf.open(QIODevice::WriteOnly);
|
conf.open(QIODevice::WriteOnly);
|
||||||
static const char *init_conf = "转啊~ 转啊~";
|
static const char *init_conf = "转啊~ 转啊~";
|
||||||
conf.write(init_conf);
|
conf.write(init_conf);
|
||||||
|
conf.close();
|
||||||
return init_conf;
|
return init_conf;
|
||||||
}
|
}
|
||||||
conf.open(QIODevice::ReadOnly);
|
conf.open(QIODevice::ReadOnly);
|
||||||
return conf.readAll();
|
auto ret = conf.readAll();
|
||||||
|
conf.close();
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlBackend::saveConf(const QString &conf) {
|
void QmlBackend::saveConf(const QString &conf) {
|
||||||
QFile c("freekill.client.config.json");
|
QFile c("freekill.client.config.json");
|
||||||
c.open(QIODevice::WriteOnly);
|
c.open(QIODevice::WriteOnly);
|
||||||
c.write(conf.toUtf8());
|
c.write(conf.toUtf8());
|
||||||
|
c.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QmlBackend::replyDelayTest(const QString &screenName,
|
void QmlBackend::replyDelayTest(const QString &screenName,
|
||||||
|
@ -308,4 +316,8 @@ void QmlBackend::installAESKey() {
|
||||||
ClientInstance->installAESKey(aes_key.toLatin1());
|
ClientInstance->installAESKey(aes_key.toLatin1());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QmlBackend::createModBackend() {
|
||||||
|
engine->rootContext()->setContextProperty("ModBackend", new ModMaker);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
#ifndef _QMLBACKEND_H
|
#ifndef _QMLBACKEND_H
|
||||||
#define _QMLBACKEND_H
|
#define _QMLBACKEND_H
|
||||||
|
|
||||||
|
#include <openssl/rsa.h>
|
||||||
|
#include <openssl/pem.h>
|
||||||
|
|
||||||
#include <qtmetamacros.h>
|
#include <qtmetamacros.h>
|
||||||
class QmlBackend : public QObject {
|
class QmlBackend : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -50,6 +53,8 @@ public:
|
||||||
Q_INVOKABLE QString getAESKey() const;
|
Q_INVOKABLE QString getAESKey() const;
|
||||||
Q_INVOKABLE void installAESKey();
|
Q_INVOKABLE void installAESKey();
|
||||||
|
|
||||||
|
Q_INVOKABLE void createModBackend();
|
||||||
|
|
||||||
qreal volume() const { return m_volume; }
|
qreal volume() const { return m_volume; }
|
||||||
void setVolume(qreal v) { m_volume = v; }
|
void setVolume(qreal v) { m_volume = v; }
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user