parent
c7e0b2fdf3
commit
fd270a2edb
23
Fk/Logic.js
23
Fk/Logic.js
|
@ -17,6 +17,29 @@ function createClientPages() {
|
|||
var callbacks = {};
|
||||
let sheduled_download = "";
|
||||
|
||||
callbacks["ServerDetected"] = (j) => {
|
||||
const serverDialog = mainStack.currentItem.serverDialog;
|
||||
if (!serverDialog) {
|
||||
return;
|
||||
}
|
||||
const item = serverDialog.item;
|
||||
if (item) {
|
||||
toast.show(qsTr("Detected Server %1").arg(j.slice(7)), 10000);
|
||||
}
|
||||
}
|
||||
|
||||
callbacks["GetServerDetail"] = (j) => {
|
||||
const [addr, ver, icon, desc, capacity, count] = JSON.parse(j);
|
||||
const serverDialog = mainStack.currentItem.serverDialog;
|
||||
if (!serverDialog) {
|
||||
return;
|
||||
}
|
||||
const item = serverDialog.item;
|
||||
if (item) {
|
||||
item.updateServerDetail(addr, [ver, icon, desc, capacity, count]);
|
||||
}
|
||||
}
|
||||
|
||||
callbacks["NetworkDelayTest"] = (jsonData) => {
|
||||
// jsonData: RSA pub key
|
||||
let cipherText;
|
||||
|
|
|
@ -6,6 +6,7 @@ import QtQuick.Controls
|
|||
|
||||
Item {
|
||||
id: root
|
||||
property alias serverDialog: serverDialogLoader
|
||||
|
||||
Item {
|
||||
width: 960 * 0.8
|
||||
|
@ -54,62 +55,17 @@ Item {
|
|||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
columns: 2
|
||||
rowSpacing: 20
|
||||
|
||||
Text {
|
||||
text: qsTr("Server Addr")
|
||||
}
|
||||
ComboBox {
|
||||
id: server_addr
|
||||
Layout.fillWidth: true
|
||||
model: []
|
||||
editable: true
|
||||
|
||||
onEditTextChanged: {
|
||||
if (model.indexOf(editText) === -1) {
|
||||
passwordEdit.text = "";
|
||||
} else {
|
||||
const data = config.savedPassword[editText];
|
||||
screenNameEdit.text = data.username;
|
||||
passwordEdit.text = data.shorten_password;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: qsTr("Username")
|
||||
}
|
||||
TextField {
|
||||
id: screenNameEdit
|
||||
maximumLength: 32
|
||||
Layout.fillWidth: true
|
||||
placeholderText: qsTr("Username")
|
||||
text: ""
|
||||
onTextChanged: {
|
||||
passwordEdit.text = "";
|
||||
const data = config.savedPassword[server_addr.editText];
|
||||
if (data) {
|
||||
if (text === data.username) {
|
||||
passwordEdit.text = data.shorten_password;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CheckBox {
|
||||
id: showPasswordCheck
|
||||
text: qsTr("Show Password")
|
||||
}
|
||||
TextField {
|
||||
id: passwordEdit
|
||||
maximumLength: 64
|
||||
Layout.fillWidth: true
|
||||
placeholderText: qsTr("Password")
|
||||
text: ""
|
||||
echoMode: showPasswordCheck.checked ? TextInput.Normal : TextInput.Password
|
||||
passwordCharacter: "*"
|
||||
Button {
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("Console start")
|
||||
onClicked: {
|
||||
config.serverAddr = "127.0.0.1";
|
||||
const serverCfg = config.savedPassword["127.0.0.1"] ?? {};
|
||||
config.screenName = serverCfg.username ?? "player";
|
||||
config.password = serverCfg.shorten_password ?? "1234";
|
||||
mainWindow.busy = true;
|
||||
Backend.startServer(9527);
|
||||
Backend.joinServer("127.0.0.1");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,38 +73,25 @@ Item {
|
|||
text: qsTr("Join Server")
|
||||
Layout.fillWidth: true
|
||||
display: AbstractButton.TextBesideIcon
|
||||
icon.name: "go-next"
|
||||
enabled: passwordEdit.text !== ""
|
||||
onClicked: {
|
||||
config.serverAddr = server_addr.editText;
|
||||
config.screenName = screenNameEdit.text;
|
||||
config.password = passwordEdit.text;
|
||||
mainWindow.busy = true;
|
||||
Backend.joinServer(server_addr.editText);
|
||||
serverDialog.show();
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Button {
|
||||
Layout.preferredWidth: 180
|
||||
text: qsTr("Console start")
|
||||
enabled: passwordEdit.text !== ""
|
||||
onClicked: {
|
||||
config.serverAddr = "127.0.0.1";
|
||||
config.screenName = screenNameEdit.text;
|
||||
config.password = passwordEdit.text;
|
||||
mainWindow.busy = true;
|
||||
Backend.startServer(9527);
|
||||
Backend.joinServer("127.0.0.1");
|
||||
}
|
||||
Button {
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("PackageManage")
|
||||
onClicked: {
|
||||
mainStack.push(packageManage);
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("PackageManage")
|
||||
onClicked: {
|
||||
mainStack.push(packageManage);
|
||||
}
|
||||
Button {
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("Quit Game")
|
||||
onClicked: {
|
||||
config.saveConf();
|
||||
Qt.quit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -183,6 +126,63 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: serverDialog
|
||||
width: parent.width * 0.8
|
||||
height: parent.height * 0.9
|
||||
anchors.centerIn: parent
|
||||
visible: false
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
opacity: 0.9
|
||||
radius: 8
|
||||
color: "snow"
|
||||
border.color: "black"
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: serverDialogLoader
|
||||
anchors.fill: parent
|
||||
source: "JoinServer.qml"
|
||||
}
|
||||
|
||||
PropertyAnimation on opacity {
|
||||
id: showAnim
|
||||
from: 0
|
||||
to: 1
|
||||
duration: 400
|
||||
running: false
|
||||
onStarted: {
|
||||
serverDialogLoader.item.loadConfig();
|
||||
}
|
||||
}
|
||||
|
||||
PropertyAnimation on opacity {
|
||||
id: hideAnim
|
||||
from: 1
|
||||
to: 0
|
||||
duration: 400
|
||||
running: false
|
||||
onFinished: {
|
||||
serverDialog.visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
function show() {
|
||||
visible = true;
|
||||
showAnim.start();
|
||||
}
|
||||
|
||||
function hide() {
|
||||
hideAnim.start();
|
||||
}
|
||||
}
|
||||
|
||||
// Temp
|
||||
Button {
|
||||
text: qsTr("Making Mod")
|
||||
|
@ -202,15 +202,5 @@ Item {
|
|||
config.loadConf();
|
||||
|
||||
lady.source = config.ladyImg;
|
||||
|
||||
server_addr.model = Object.keys(config.savedPassword);
|
||||
server_addr.onModelChanged();
|
||||
server_addr.currentIndex = server_addr.model.indexOf(config.lastLoginServer);
|
||||
|
||||
const data = config.savedPassword[config.lastLoginServer];
|
||||
if (data) {
|
||||
screenNameEdit.text = data.username;
|
||||
passwordEdit.text = data.shorten_password;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,384 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
|
||||
Item {
|
||||
id: root
|
||||
anchors.fill: parent
|
||||
|
||||
Timer {
|
||||
id: opTimer
|
||||
interval: 5000
|
||||
}
|
||||
|
||||
Component {
|
||||
id: serverDelegate
|
||||
|
||||
Item {
|
||||
height: 64
|
||||
width: serverList.width - 48
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 16
|
||||
|
||||
Image {
|
||||
Layout.preferredHeight: 60
|
||||
Layout.preferredWidth: 60
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: favicon
|
||||
}
|
||||
|
||||
Text {
|
||||
text: serverIP
|
||||
}
|
||||
|
||||
Text {
|
||||
text: description
|
||||
}
|
||||
|
||||
Text {
|
||||
text: online + "/" + capacity
|
||||
}
|
||||
}
|
||||
|
||||
TapHandler {
|
||||
onTapped: {
|
||||
if (serverList.currentIndex === index) {
|
||||
serverList.currentIndex = -1;
|
||||
} else {
|
||||
serverList.currentIndex = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ListView {
|
||||
id: serverList
|
||||
height: parent.height - controlPanel.height - 30
|
||||
width: parent.width - 80
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 10
|
||||
contentHeight: serverDelegate.height * count
|
||||
model: ListModel {
|
||||
id: serverModel
|
||||
}
|
||||
delegate: serverDelegate
|
||||
ScrollBar.vertical: ScrollBar {}
|
||||
clip: true
|
||||
highlight: Rectangle {
|
||||
color: "transparent"; radius: 5
|
||||
border.color: "black"; border.width: 2
|
||||
}
|
||||
highlightMoveDuration: 0
|
||||
currentIndex: -1
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
id: controlPanel
|
||||
anchors.top: serverList.bottom
|
||||
anchors.topMargin: 10
|
||||
width: parent.width - 80
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
height: joinButton.height * 2 + 10
|
||||
columns: 3
|
||||
|
||||
Button {
|
||||
id: joinButton
|
||||
Layout.fillWidth: true
|
||||
enabled: serverList.currentIndex !== -1
|
||||
text: qsTr("Join Server")
|
||||
onClicked: {
|
||||
const item = serverModel.get(serverList.currentIndex);
|
||||
const serverCfg = config.savedPassword[item.serverIP];
|
||||
config.serverAddr = item.serverIP;
|
||||
config.screenName = serverCfg.username;
|
||||
config.password = serverCfg.shorten_password ?? serverCfg.password;
|
||||
mainWindow.busy = true;
|
||||
Backend.joinServer(item.serverIP);
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("Add New Server")
|
||||
onClicked: {
|
||||
drawerLoader.sourceComponent = newServerComponent;
|
||||
drawer.open();
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
Layout.fillWidth: true
|
||||
enabled: serverList.currentIndex !== -1
|
||||
text: qsTr("Edit Server")
|
||||
onClicked: {
|
||||
drawerLoader.sourceComponent = editServerComponent;
|
||||
drawer.open();
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("Refresh List")
|
||||
enabled: !opTimer.running
|
||||
onClicked: {
|
||||
opTimer.start();
|
||||
for (let i = 0; i < serverModel.count; i++) {
|
||||
const item = serverModel.get(i);
|
||||
Backend.getServerInfo(item.serverIP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("Detect LAN")
|
||||
enabled: !opTimer.running
|
||||
onClicked: {
|
||||
opTimer.start();
|
||||
Backend.detectServer();
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("Go Back")
|
||||
onClicked: serverDialog.hide();
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: newServerComponent
|
||||
ColumnLayout {
|
||||
signal finished();
|
||||
|
||||
Text {
|
||||
text: qsTr("@NewServer")
|
||||
font.pixelSize: 24
|
||||
font.bold: true
|
||||
Layout.fillWidth: true
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
Text {
|
||||
text: qsTr("@NewServerHint")
|
||||
font.pixelSize: 16
|
||||
Layout.fillWidth: true
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: serverAddrEdit
|
||||
Layout.fillWidth: true
|
||||
placeholderText: qsTr("Server Addr")
|
||||
text: ""
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: screenNameEdit
|
||||
maximumLength: 32
|
||||
Layout.fillWidth: true
|
||||
placeholderText: qsTr("Username")
|
||||
text: ""
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: passwordEdit
|
||||
maximumLength: 64
|
||||
Layout.fillWidth: true
|
||||
placeholderText: qsTr("Password")
|
||||
text: ""
|
||||
echoMode: showPasswordCheck.checked ? TextInput.Normal : TextInput.Password
|
||||
passwordCharacter: "*"
|
||||
}
|
||||
|
||||
CheckBox {
|
||||
id: showPasswordCheck
|
||||
text: qsTr("Show Password")
|
||||
}
|
||||
|
||||
Button {
|
||||
Layout.fillWidth: true
|
||||
enabled: serverAddrEdit.text !== "" && screenNameEdit.text !== "" && passwordEdit.text !== ""
|
||||
text: "OK"
|
||||
onClicked: {
|
||||
root.addNewServer(serverAddrEdit.text, screenNameEdit.text, passwordEdit.text);
|
||||
finished();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: editServerComponent
|
||||
ColumnLayout {
|
||||
signal finished();
|
||||
|
||||
Text {
|
||||
text: qsTr("@EditServer")
|
||||
font.pixelSize: 24
|
||||
font.bold: true
|
||||
Layout.fillWidth: true
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
Text {
|
||||
text: qsTr("@EditServerHint")
|
||||
font.pixelSize: 16
|
||||
Layout.fillWidth: true
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: screenNameEdit
|
||||
maximumLength: 32
|
||||
Layout.fillWidth: true
|
||||
placeholderText: qsTr("Username")
|
||||
text: ""
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: passwordEdit
|
||||
maximumLength: 64
|
||||
Layout.fillWidth: true
|
||||
placeholderText: qsTr("Password")
|
||||
text: ""
|
||||
echoMode: showPasswordCheck.checked ? TextInput.Normal : TextInput.Password
|
||||
passwordCharacter: "*"
|
||||
}
|
||||
|
||||
CheckBox {
|
||||
id: showPasswordCheck
|
||||
text: qsTr("Show Password")
|
||||
}
|
||||
|
||||
Button {
|
||||
Layout.fillWidth: true
|
||||
enabled: screenNameEdit.text !== "" && passwordEdit.text !== ""
|
||||
text: "OK"
|
||||
onClicked: {
|
||||
root.editCurrentServer(screenNameEdit.text, passwordEdit.text);
|
||||
finished();
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("Delete Server")
|
||||
onClicked: {
|
||||
root.deleteCurrentServer();
|
||||
finished();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Drawer {
|
||||
id: drawer
|
||||
width: parent.width * 0.3 / mainWindow.scale
|
||||
height: parent.height / mainWindow.scale
|
||||
dim: false
|
||||
clip: true
|
||||
dragMargin: 0
|
||||
scale: mainWindow.scale
|
||||
transformOrigin: Item.TopLeft
|
||||
|
||||
Loader {
|
||||
id: drawerLoader
|
||||
anchors.fill: parent
|
||||
anchors.margins: 16
|
||||
onSourceChanged: {
|
||||
if (item === null)
|
||||
return;
|
||||
item.finished.connect(() => {
|
||||
sourceComponent = undefined;
|
||||
drawer.close();
|
||||
});
|
||||
}
|
||||
onSourceComponentChanged: sourceChanged();
|
||||
}
|
||||
}
|
||||
|
||||
function addNewServer(addr, name, password) {
|
||||
if (config.savedPassword[addr]) {
|
||||
return;
|
||||
}
|
||||
|
||||
config.savedPassword[addr] = {
|
||||
username: name,
|
||||
password: password,
|
||||
};
|
||||
config.saveConf();
|
||||
|
||||
serverModel.append({
|
||||
serverIP: addr,
|
||||
description: qsTr("Server not up"),
|
||||
online: "-",
|
||||
capacity: "-",
|
||||
favicon: "https://img1.imgtp.com/2023/07/01/DGUdj8eu.png",
|
||||
});
|
||||
Backend.getServerInfo(addr);
|
||||
}
|
||||
|
||||
function editCurrentServer(name, password) {
|
||||
const addr = serverModel.get(serverList.currentIndex).serverIP;
|
||||
if (!config.savedPassword[addr]) {
|
||||
return;
|
||||
}
|
||||
|
||||
config.savedPassword[addr] = {
|
||||
username: name,
|
||||
password: password,
|
||||
shorten_password: undefined,
|
||||
key: undefined,
|
||||
};
|
||||
config.saveConf();
|
||||
}
|
||||
|
||||
function deleteCurrentServer() {
|
||||
const addr = serverModel.get(serverList.currentIndex).serverIP;
|
||||
if (!config.savedPassword[addr]) {
|
||||
return;
|
||||
}
|
||||
|
||||
config.savedPassword[addr] = undefined;
|
||||
config.saveConf();
|
||||
|
||||
serverModel.remove(serverList.currentIndex, 1);
|
||||
serverList.currentIndex = -1;
|
||||
}
|
||||
|
||||
function updateServerDetail(addr, data) {
|
||||
const [ver, icon, desc, capacity, count] = data;
|
||||
for (let i = 0; i < serverModel.count; i++) {
|
||||
const item = serverModel.get(i);
|
||||
if (addr.endsWith(item.serverIP)) { // endsWith是为了应付IPv6格式的ip
|
||||
item.description = FkVersion === ver ? desc : "Ver " + ver;
|
||||
item.favicon = icon;
|
||||
item.online = count.toString();
|
||||
item.capacity = capacity.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function loadConfig() {
|
||||
if (serverModel.count > 0) {
|
||||
return;
|
||||
}
|
||||
for (let key in config.savedPassword) {
|
||||
serverModel.append({
|
||||
serverIP: key,
|
||||
description: qsTr("Server not up"),
|
||||
online: "-",
|
||||
capacity: "-",
|
||||
favicon: "https://img1.imgtp.com/2023/07/01/DGUdj8eu.png",
|
||||
});
|
||||
Backend.getServerInfo(key);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -298,9 +298,13 @@ Item {
|
|||
width: childrenRect.width
|
||||
height: childrenRect.height
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 8
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 8
|
||||
ColumnLayout {
|
||||
MetroButton {
|
||||
text: Backend.translate("Revert Selection")
|
||||
textFont.pixelSize: 28
|
||||
enabled: dashboard.pending_skill !== ""
|
||||
onClicked: dashboard.revertSelection();
|
||||
}
|
||||
|
@ -309,9 +313,11 @@ Item {
|
|||
// }
|
||||
MetroButton {
|
||||
text: Backend.translate("Sort Cards")
|
||||
textFont.pixelSize: 28
|
||||
}
|
||||
MetroButton {
|
||||
text: Backend.translate("Chat")
|
||||
textFont.pixelSize: 28
|
||||
onClicked: roomDrawer.open();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -115,26 +115,22 @@
|
|||
<source>FreeKill</source>
|
||||
<translation>新月杀</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Username</source>
|
||||
<translation>用户名</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Show Password</source>
|
||||
<translation>显示密码</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Join Server</source>
|
||||
<translation>加入服务器</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Console start</source>
|
||||
<translation>单机启动</translation>
|
||||
<translation>单机启动(不推荐)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>PackageManage</source>
|
||||
<translation>管理拓展包</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Quit Game</source>
|
||||
<translation>退出游戏</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Making Mod</source>
|
||||
<translation>制作Mod</translation>
|
||||
|
@ -143,10 +139,6 @@
|
|||
<source>Welcome back!</source>
|
||||
<translation>欢迎回来!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Server Addr</source>
|
||||
<translation>服务器IP</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>FAQ</source>
|
||||
<translation>常见疑问</translation>
|
||||
|
@ -169,6 +161,77 @@
|
|||
</message>
|
||||
</context>
|
||||
|
||||
<context>
|
||||
<name>JoinServer</name>
|
||||
<message>
|
||||
<source>Join Server</source>
|
||||
<translation>加入服务器</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Add New Server</source>
|
||||
<translation>添加服务器</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Edit Server</source>
|
||||
<translation>编辑服务器</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Refresh List</source>
|
||||
<translation>刷新列表</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Detect LAN</source>
|
||||
<translation>探测局域网</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Go Back</source>
|
||||
<translation>返回</translation>
|
||||
</message>
|
||||
|
||||
<message>
|
||||
<source>Server not up</source>
|
||||
<translation>服务器似乎没有启动。</translation>
|
||||
</message>
|
||||
|
||||
<message>
|
||||
<source>@NewServer</source>
|
||||
<translation>添加新服务器</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>@NewServerHint</source>
|
||||
<translation>请输入服务器的IP或者域名,并输入你在这个服务器所使用的用户名与密码。如果你之前并未游玩过该服务器,则服务器会为你自动注册一个账号。以后登陆到该服务器都需要同样的用户名和密码,请不要忘记密码!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Server Addr</source>
|
||||
<translation>服务器IP</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Username</source>
|
||||
<translation>用户名</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Password</source>
|
||||
<translation>密码</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Show Password</source>
|
||||
<translation>显示密码</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>@EditServer</source>
|
||||
<translation>编辑服务器</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>@EditServerHint</source>
|
||||
<translation>你可以修改在该服务器使用的用户名与密码。
|
||||
你不能直接修改服务器的IP;如确实需要,请删除此服务器然后新增一个。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Delete Server</source>
|
||||
<translation>删除服务器</translation>
|
||||
</message>
|
||||
</context>
|
||||
|
||||
<context>
|
||||
<name>main</name>
|
||||
<message>
|
||||
|
@ -207,6 +270,10 @@
|
|||
|
||||
<context>
|
||||
<name>Logic</name>
|
||||
<message>
|
||||
<source>Detected Server %1</source>
|
||||
<translation>检测到新月杀服务器 - %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>MD5 check failed!</source>
|
||||
<translation>MD5检测失败!请与服务端保持一致后再登入</translation>
|
||||
|
|
|
@ -418,7 +418,7 @@ end
|
|||
--- 通过 二者位次+距离技能之和 与 两者间固定距离 进行对比,更大的为实际距离。
|
||||
---@param other Player @ 其他玩家
|
||||
function Player:distanceTo(other)
|
||||
-- assert(other:isInstanceOf(Player))
|
||||
assert(other:isInstanceOf(Player))
|
||||
if other == self then return 0 end
|
||||
local right = 0
|
||||
local temp = self
|
||||
|
|
|
@ -41,6 +41,7 @@ function GameLogic:run()
|
|||
local room = self.room
|
||||
table.shuffle(self.room.players)
|
||||
self:assignRoles()
|
||||
self.room.game_started = true
|
||||
room:doBroadcastNotify("StartGame", "")
|
||||
room:adjustSeats()
|
||||
|
||||
|
@ -52,7 +53,6 @@ function GameLogic:run()
|
|||
self:attachSkillToPlayers()
|
||||
self:prepareForStart()
|
||||
|
||||
self.room.game_started = true
|
||||
self:action()
|
||||
end
|
||||
|
||||
|
|
|
@ -4,8 +4,8 @@ local function tellRoomToObserver(self, player)
|
|||
local observee = self.players[1]
|
||||
player:doNotify("Setup", json.encode{
|
||||
observee.id,
|
||||
observee.serverplayer:getScreenName(),
|
||||
observee.serverplayer:getAvatar(),
|
||||
observee._splayer:getScreenName(),
|
||||
observee._splayer:getAvatar(),
|
||||
})
|
||||
player:doNotify("EnterRoom", json.encode{
|
||||
#self.players, self.timeout, self.settings
|
||||
|
@ -16,8 +16,8 @@ local function tellRoomToObserver(self, player)
|
|||
for _, p in ipairs(self:getOtherPlayers(observee, true, true)) do
|
||||
player:doNotify("AddPlayer", json.encode{
|
||||
p.id,
|
||||
p.serverplayer:getScreenName(),
|
||||
p.serverplayer:getAvatar(),
|
||||
p._splayer:getScreenName(),
|
||||
p._splayer:getAvatar(),
|
||||
})
|
||||
end
|
||||
|
||||
|
|
|
@ -131,8 +131,9 @@ function Room:resume()
|
|||
end
|
||||
|
||||
::GAME_OVER::
|
||||
coroutine.close(main_co)
|
||||
self.main_co = nil
|
||||
self:gameOver("")
|
||||
-- coroutine.close(main_co)
|
||||
-- self.main_co = nil
|
||||
return true
|
||||
end
|
||||
|
||||
|
@ -169,7 +170,7 @@ function Room:isReady()
|
|||
rest = p.request_timeout * 1000 - (os.getms() -
|
||||
p.request_start) / 1000
|
||||
|
||||
if rest <= 0 then
|
||||
if rest <= 0 or p.serverplayer:getState() ~= fk.Player_Online then
|
||||
p._splayer:setThinking(false)
|
||||
end
|
||||
end
|
||||
|
@ -208,6 +209,7 @@ end
|
|||
--- 当这个函数返回之后,整个Room线程也宣告结束。
|
||||
---@return nil
|
||||
function Room:run()
|
||||
self.start_time = os.time()
|
||||
for _, p in fk.qlist(self.room:getPlayers()) do
|
||||
local player = ServerPlayer:new(p)
|
||||
player.room = self
|
||||
|
@ -2863,6 +2865,9 @@ local function shouldUpdateWinRate(room)
|
|||
if room.settings.enableFreeAssign then
|
||||
return false
|
||||
end
|
||||
if os.time() - room.start_time < 45 then
|
||||
return false
|
||||
end
|
||||
for _, p in ipairs(room.players) do
|
||||
if p.id < 0 then return false end
|
||||
end
|
||||
|
|
|
@ -284,8 +284,8 @@ function ServerPlayer:reconnect()
|
|||
|
||||
self:doNotify("Setup", json.encode{
|
||||
self.id,
|
||||
self.serverplayer:getScreenName(),
|
||||
self.serverplayer:getAvatar(),
|
||||
self._splayer:getScreenName(),
|
||||
self._splayer:getAvatar(),
|
||||
})
|
||||
self:doNotify("EnterLobby", "")
|
||||
self:doNotify("EnterRoom", json.encode{
|
||||
|
@ -298,8 +298,8 @@ function ServerPlayer:reconnect()
|
|||
for _, p in ipairs(room:getOtherPlayers(self, true, true)) do
|
||||
self:doNotify("AddPlayer", json.encode{
|
||||
p.id,
|
||||
p.serverplayer:getScreenName(),
|
||||
p.serverplayer:getAvatar(),
|
||||
p._splayer:getScreenName(),
|
||||
p._splayer:getAvatar(),
|
||||
})
|
||||
end
|
||||
|
||||
|
|
|
@ -267,7 +267,7 @@ void Room::removePlayer(ServerPlayer *player) {
|
|||
server->addPlayer(runner);
|
||||
|
||||
// 如果走小道的人不是单机启动玩家 那么直接ban
|
||||
if (!runner->getSocket()->peerAddress().contains("127.0.0.1")) {
|
||||
if (!runner->getSocket()->peerAddress().contains("127.0.0.1") && !player->isDied()) {
|
||||
server->temporarilyBan(runner->getId());
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,11 @@ Server::Server(QObject *parent) : QObject(parent) {
|
|||
connect(server, &ServerSocket::new_connection, this,
|
||||
&Server::processNewConnection);
|
||||
|
||||
udpSocket = new QUdpSocket(this);
|
||||
udpSocket->bind(9527);
|
||||
connect(udpSocket, &QUdpSocket::readyRead,
|
||||
this, &Server::readPendingDatagrams);
|
||||
|
||||
// 创建第一个房间,这个房间作为“大厅房间”
|
||||
nextRoomId = 0;
|
||||
createRoom(nullptr, "Lobby", INT32_MAX);
|
||||
|
@ -520,6 +525,7 @@ void Server::onUserDisconnected() {
|
|||
player->setSocket(nullptr);
|
||||
// TODO: add a robot
|
||||
} else {
|
||||
player->setState(Player::Robot); // 大厅!然而又不能设Offline
|
||||
player->deleteLater();
|
||||
}
|
||||
}
|
||||
|
@ -575,6 +581,9 @@ void Server::readConfig() {
|
|||
config = QJsonDocument::fromJson(json).object();
|
||||
|
||||
// defaults
|
||||
SET_DEFAULT_CONFIG("description", "FreeKill Server");
|
||||
SET_DEFAULT_CONFIG("iconUrl", "https://img1.imgtp.com/2023/07/01/DGUdj8eu.png");
|
||||
SET_DEFAULT_CONFIG("capacity", 100);
|
||||
SET_DEFAULT_CONFIG("tempBanTime", 20);
|
||||
}
|
||||
|
||||
|
@ -610,3 +619,27 @@ void Server::temporarilyBan(int playerId) {
|
|||
});
|
||||
emit player->kicked();
|
||||
}
|
||||
|
||||
void Server::readPendingDatagrams() {
|
||||
while (udpSocket->hasPendingDatagrams()) {
|
||||
QNetworkDatagram datagram = udpSocket->receiveDatagram();
|
||||
if (datagram.isValid()) {
|
||||
processDatagram(datagram.data(), datagram.senderAddress(), datagram.senderPort());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Server::processDatagram(const QByteArray &msg, const QHostAddress &addr, uint port) {
|
||||
if (msg == "fkDetectServer") {
|
||||
udpSocket->writeDatagram("me", addr, port);
|
||||
} else if (msg == "fkGetDetail") {
|
||||
udpSocket->writeDatagram(JsonArray2Bytes(QJsonArray({
|
||||
FK_VERSION,
|
||||
getConfig("iconUrl"),
|
||||
getConfig("description"),
|
||||
getConfig("capacity"),
|
||||
players.count(),
|
||||
})), addr, port);
|
||||
}
|
||||
udpSocket->flush();
|
||||
}
|
||||
|
|
|
@ -54,6 +54,7 @@ signals:
|
|||
public slots:
|
||||
void processNewConnection(ClientSocket *client);
|
||||
void processRequest(const QByteArray &msg);
|
||||
void readPendingDatagrams();
|
||||
|
||||
void onRoomAbandoned();
|
||||
void onUserDisconnected();
|
||||
|
@ -62,6 +63,8 @@ public slots:
|
|||
private:
|
||||
friend class Shell;
|
||||
ServerSocket *server;
|
||||
QUdpSocket *udpSocket;
|
||||
|
||||
Room *m_lobby;
|
||||
QMap<int, Room *> rooms;
|
||||
QStack<Room *> idle_rooms;
|
||||
|
@ -83,6 +86,7 @@ private:
|
|||
|
||||
void handleNameAndPassword(ClientSocket *client, const QString &name,
|
||||
const QString &password, const QString &md5_str);
|
||||
void processDatagram(const QByteArray &msg, const QHostAddress &addr, uint port);
|
||||
};
|
||||
|
||||
extern Server *ServerInstance;
|
||||
|
|
|
@ -318,6 +318,11 @@ void Shell::run() {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!strcmp(bytes, "crash")) {
|
||||
qFatal("Crashing."); // should dump core
|
||||
return;
|
||||
}
|
||||
|
||||
if (*bytes)
|
||||
add_history(bytes);
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "qmlbackend.h"
|
||||
#include <qjsondocument.h>
|
||||
|
||||
#ifndef FK_SERVER_ONLY
|
||||
#include <qaudiooutput.h>
|
||||
|
@ -26,6 +27,10 @@ QmlBackend::QmlBackend(QObject *parent) : QObject(parent) {
|
|||
#ifndef FK_SERVER_ONLY
|
||||
engine = nullptr;
|
||||
rsa = RSA_new();
|
||||
udpSocket = new QUdpSocket(this);
|
||||
udpSocket->bind(0);
|
||||
connect(udpSocket, &QUdpSocket::readyRead,
|
||||
this, &QmlBackend::readPendingDatagrams);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -320,4 +325,50 @@ void QmlBackend::createModBackend() {
|
|||
engine->rootContext()->setContextProperty("ModBackend", new ModMaker);
|
||||
}
|
||||
|
||||
|
||||
void QmlBackend::detectServer() {
|
||||
static const char *ask_str = "fkDetectServer";
|
||||
udpSocket->writeDatagram(ask_str,
|
||||
strlen(ask_str),
|
||||
QHostAddress::Broadcast,
|
||||
9527);
|
||||
}
|
||||
|
||||
void QmlBackend::getServerInfo(const QString &address) {
|
||||
QString addr = "127.0.0.1";
|
||||
ushort port = 9527u;
|
||||
static const char *ask_str = "fkGetDetail";
|
||||
|
||||
if (address.contains(QChar(':'))) {
|
||||
QStringList texts = address.split(QChar(':'));
|
||||
addr = texts.value(0);
|
||||
port = texts.value(1).toUShort();
|
||||
} else {
|
||||
addr = address;
|
||||
}
|
||||
|
||||
udpSocket->writeDatagram(ask_str,
|
||||
strlen(ask_str),
|
||||
QHostAddress(addr), port);
|
||||
}
|
||||
|
||||
void QmlBackend::readPendingDatagrams() {
|
||||
while (udpSocket->hasPendingDatagrams()) {
|
||||
QNetworkDatagram datagram = udpSocket->receiveDatagram();
|
||||
if (datagram.isValid()) {
|
||||
auto data = datagram.data();
|
||||
auto addr = datagram.senderAddress();
|
||||
// auto port = datagram.senderPort();
|
||||
|
||||
if (data == "me") {
|
||||
emit notifyUI("ServerDetected", addr.toString());
|
||||
} else {
|
||||
auto arr = QJsonDocument::fromJson(data).array();
|
||||
arr.prepend(addr.toString());
|
||||
emit notifyUI("GetServerDetail", JsonArray2Bytes(arr));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -55,6 +55,9 @@ public:
|
|||
|
||||
Q_INVOKABLE void createModBackend();
|
||||
|
||||
Q_INVOKABLE void detectServer();
|
||||
Q_INVOKABLE void getServerInfo(const QString &addr);
|
||||
|
||||
qreal volume() const { return m_volume; }
|
||||
void setVolume(qreal v) { m_volume = v; }
|
||||
|
||||
|
@ -64,10 +67,15 @@ signals:
|
|||
void notifyUI(const QString &command, const QString &jsonData);
|
||||
void volumeChanged(qreal);
|
||||
|
||||
private slots:
|
||||
void readPendingDatagrams();
|
||||
|
||||
private:
|
||||
Q_PROPERTY(qreal volume READ volume WRITE setVolume NOTIFY volumeChanged)
|
||||
|
||||
QQmlApplicationEngine *engine;
|
||||
|
||||
QUdpSocket *udpSocket;
|
||||
RSA *rsa;
|
||||
QString aes_key;
|
||||
qreal m_volume;
|
||||
|
|
Loading…
Reference in New Issue