From 951a9a04974fd3f3777570cd4ec18f741ed3a868 Mon Sep 17 00:00:00 2001 From: notify Date: Sun, 13 Oct 2024 10:38:55 +0800 Subject: [PATCH] UI rewrite2 (#371) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 基本上能玩了 --------- Co-authored-by: YoumuKon <38815081+YoumuKon@users.noreply.github.com> --- Fk/Pages/Room.qml | 86 ++----- Fk/Pages/RoomLogic.js | 383 +++----------------------------- Fk/RoomElement/HandcardArea.qml | 4 +- src/client/client.h | 2 + src/network/router.cpp | 7 +- src/network/router.h | 10 +- src/server/serverplayer.cpp | 4 +- src/server/serverplayer.h | 2 +- src/swig/freekill-nogui.i | 3 +- src/swig/freekill.i | 3 +- src/swig/naturalvar.i | 14 +- src/swig/server.i | 2 +- src/ui/qmlbackend.cpp | 11 + src/ui/qmlbackend.h | 2 + 14 files changed, 100 insertions(+), 433 deletions(-) diff --git a/Fk/Pages/Room.qml b/Fk/Pages/Room.qml index 45519d71..d5a457e7 100644 --- a/Fk/Pages/Room.qml +++ b/Fk/Pages/Room.qml @@ -314,15 +314,15 @@ Item { state: "notactive" transitions: [ Transition { - from: "active"; to: "notactive" + from: "*"; to: "notactive" ScriptAction { script: { skillInteraction.sourceComponent = undefined; promptText = ""; - progress.visible = false; okCancel.visible = false; endPhaseButton.visible = false; progress.visible = false; + extra_data = {}; dashboard.disableAllCards(); dashboard.disableSkills(); @@ -348,6 +348,12 @@ Item { from: "notactive"; to: "active" ScriptAction { script: { + const dat = Backend.getRequestData(); + const total = dat["timeout"] * 1000; + const now = Date.now(); // ms + const elapsed = now - (dat["timestamp"] ?? now); + progressAnim.from = (1 - elapsed / total) * 100.0; + progressAnim.duration = total - elapsed; progress.visible = true; } } @@ -402,7 +408,6 @@ Item { sealedSlots: JSON.parse(model.sealedSlots) onSelectedChanged: { - // Logic.updateSelectedTargets(playerid, selected); if ( state === "candidate" ) lcall("UpdateRequestUI", "Photo", playerid, "click", { selected } ); } @@ -455,6 +460,7 @@ Item { onClicked: roomScene.startCheat("../RoomElement/ChooseHandcard"); } MetroButton { + id: revertSelectionBtn text: luatr("Revert Selection") textFont.pixelSize: 28 enabled: dashboard.pending_skill !== "" @@ -542,29 +548,6 @@ Item { width: roomScene.width - dashboardBtn.width anchors.top: roomArea.bottom anchors.left: dashboardBtn.right - - onCardSelected: function(card) { - Logic.enableTargets(card); - if (typeof card === "number" && card !== -1 - && roomScene.state === "playing" - && lcall("GetPlayerHandcards", Self.id).includes(card)) { - - const skills = lcall("GetCardSpecialSkills", card); - if (lcall("CanUseCard", card, Self.id, - JSON.stringify(roomScene.extra_data))) { - skills.unshift("_normal_use"); - } - specialCardSkills.model = skills; - const skillName = lcall("GetCardSkill", card); - const prompt = lcall("ActiveSkillPrompt", skillName, card, - selected_targets); - if (prompt !== "") { - roomScene.setPrompt(Util.processPrompt(prompt)); - } - } else { - specialCardSkills.model = []; - } - } } Rectangle { @@ -684,6 +667,7 @@ Item { } NumberAnimation on value { + id: progressAnim running: progress.visible from: 100.0 to: 0.0 @@ -703,7 +687,7 @@ Item { color: "#88EEEEEE" radius: 8 visible: { - if (roomScene.state !== "playing") { + if (roomScene.state !== "active") { return false; } if (!specialCardSkills) { @@ -727,25 +711,7 @@ Item { text: luatr(modelData) checked: index === 0 onCheckedChanged: { - roomScene.resetPrompt(); - const card = dashboard.selected_card; - let prompt = "" - if (modelData === "_normal_use") { - Logic.enableTargets(card); - const skillName = lcall("GetCardSkill", card); - prompt = lcall("ActiveSkillPrompt", skillName, card, - selected_targets); - } else { - Logic.enableTargets(JSON.stringify({ - skill: modelData, - subcards: [card], - })); - prompt = lcall("ActiveSkillPrompt", modelData, card, - selected_targets); - } - if (prompt !== "") { - roomScene.setPrompt(Util.processPrompt(prompt)); - } + lcall("UpdateRequestUI", "SpecialSkills", "1", "click", modelData); } } } @@ -774,7 +740,7 @@ Item { && !skippedUseEventId.find(id => id === extra_data.useEventId) onClicked: { skippedUseEventId.push(extra_data.useEventId); - // Logic.doCancelButton(); + lcall("UpdateRequestUI", "Button", "Cancel"); } } @@ -1112,21 +1078,6 @@ Item { onActivated: menuContainer.open(); } - function getCurrentCardUseMethod() { - if (specialCardSkills.count === 1 - && specialCardSkills.model[0] !== "_normal_use") { - return specialCardSkills.model[0]; - } - - for (let i = 1; i < specialCardSkills.count; i++) { - const item = specialCardSkills.itemAt(i); - if (item.checked) { - const ret = item.orig_text; - return ret; - } - } - } - function addToChat(pid, raw, msg) { if (raw.type === 1) return; const photo = Logic.getPhoto(pid); @@ -1336,7 +1287,6 @@ Item { } function applyChange(uiUpdate) { - //console.log(JSON.stringify(uiUpdate)) uiUpdate["_delete"]?.forEach(data => { if (data.type == "Interaction") { skillInteraction.sourceComponent = undefined; @@ -1381,6 +1331,11 @@ Item { } }); + const sskilldata = uiUpdate["SpecialSkills"]?.[0] + if (sskilldata) { + specialCardSkills.model = sskilldata?.skills ?? []; + } + dashboard.applyChange(uiUpdate); const pdatas = uiUpdate["Photo"]; pdatas?.forEach(pdata => { @@ -1390,6 +1345,11 @@ Item { photo.selected = pdata.selected; }) const buttons = uiUpdate["Button"]; + if (buttons) { + okCancel.visible = true; + okButton.enabled = false; + cancelButton.enabled = false; + } buttons?.forEach(bdata => { switch (bdata.id) { case "OK": diff --git a/Fk/Pages/RoomLogic.js b/Fk/Pages/RoomLogic.js index ec7df083..f8c7b638 100644 --- a/Fk/Pages/RoomLogic.js +++ b/Fk/Pages/RoomLogic.js @@ -134,77 +134,6 @@ function arrangePhotos() { } } -// function doOkButton() { -// if (roomScene.state === "playing" || roomScene.state === "responding") { -// const reply = JSON.stringify({ -// card: dashboard.getSelectedCard(), -// targets: selected_targets, -// special_skill: roomScene.getCurrentCardUseMethod(), -// interaction_data: roomScene.skillInteraction.item ? -// roomScene.skillInteraction.item.answer : undefined, -// }); -// replyToServer(reply); -// return; -// } -// if (roomScene.extra_data.luckCard) { -// okButton.enabled = false; -// ClientInstance.notifyServer("PushRequest", [ -// "luckcard", true -// ].join(",")); - -// if (roomScene.extra_data.time === 1) { -// roomScene.state = "notactive"; -// } - -// return; -// } -// replyToServer("1"); -// } - -// let _is_canceling = false; -// function doCancelButton() { -// if (_is_canceling) return; -// _is_canceling = true; - - // if (roomScene.state === "playing") { - // dashboard.stopPending(); - // dashboard.deactivateSkillButton(); - // dashboard.unSelectAll(); - // dashboard.enableCards(); - // dashboard.enableSkills(); - - // _is_canceling = false; - // return; - // } else if (roomScene.state === "responding") { - // const p = dashboard.pending_skill; - // dashboard.stopPending(); - // dashboard.deactivateSkillButton(); - // dashboard.unSelectAll(); - // if (roomScene.autoPending || !p) { - // replyToServer("__cancel"); - // } else { - // dashboard.enableCards(roomScene.responding_card); - // dashboard.enableSkills(roomScene.responding_card); - // } - - // _is_canceling = false; - // return; - // } - - // if (roomScene.extra_data.luckCard) { - // ClientInstance.notifyServer("PushRequest", [ - // "luckcard", false - // ].join(",")); - // roomScene.state = "notactive"; - - // _is_canceling = false; - // return; - // } - - // replyToServer("__cancel"); - // _is_canceling = false; - // } - function replyToServer(jsonData) { ClientInstance.replyToServer("", jsonData); if (!mainWindow.is_pending) { @@ -693,239 +622,6 @@ callbacks["AddPlayer"] = (data) => { } } -/* -// card: int | { skill: string, subcards: int[] } -function enableTargets(card) { - if (roomScene.respond_play) { - const candidate = (!isNaN(card) && card !== -1) - || typeof(card) === "string"; - if (candidate) { - okButton.enabled = - lcall("CardFitPattern", card, roomScene.responding_card) && - !lcall("CardProhibitedResponse", card); - } else { - okButton.enabled = false; - } - return; - } - - let i = 0; - const candidate = (!isNaN(card) && card !== -1) || typeof(card) === "string"; - const all_photos = []; - for (i = 0; i < playerNum; i++) { - all_photos.push(photos.itemAt(i)) - } - selected_targets = []; - for (i = 0; i < playerNum; i++) { - all_photos[i].selected = false; - } - - if (candidate) { - const data = { - ok_enabled: false, - enabled_targets: [] - } - - all_photos.forEach(photo => { - photo.state = "candidate"; - const id = photo.playerid; - const ret = lcall("CanUseCardToTarget", card, id, selected_targets, - JSON.stringify(roomScene.extra_data)); - photo.selectable = ret; - - let tipText = lcall("GetUseCardTargetTip", card, id, selected_targets, - ret, JSON.stringify(roomScene.extra_data)); - if (tipText) { - photo.targetTip = tipText; - } else { - photo.targetTip = []; - } - - if (roomScene.extra_data instanceof Object) { - const must = roomScene.extra_data.must_targets; - const included = roomScene.extra_data.include_targets; - const exclusive = roomScene.extra_data.exclusive_targets; - if (exclusive instanceof Array) { - if (exclusive.indexOf(id) === -1) photo.selectable = false; - } - if (must instanceof Array) { - if (must.filter((val) => { - return selected_targets.indexOf(val) === -1; - }).length !== 0 && must.indexOf(id) === -1) photo.selectable = false; - } - if (included instanceof Array) { - if (included.filter((val) => { - return selected_targets.indexOf(val) !== -1; - }).length === 0 && included.indexOf(id) === -1) - photo.selectable = false; - } - } - }) - - okButton.enabled = lcall("CardFeasible", card, selected_targets); - if (okButton.enabled && roomScene.state === "responding") { - okButton.enabled = - lcall("CardFitPattern", card, roomScene.responding_card) && - (roomScene.autoPending || !lcall("CardProhibitedUse", card)); - } else if (okButton.enabled && roomScene.state === "playing") { - okButton.enabled = lcall("CanUseCard", card, Self.id, - JSON.stringify(roomScene.extra_data)); - } - if (okButton.enabled) { - if (roomScene.extra_data instanceof Object) { - const must = roomScene.extra_data.must_targets; - const included = roomScene.extra_data.include_targets; - if (must instanceof Array) { - if(must.length === 0) okButton.enabled = false; - } - if (included instanceof Array) { - if (included.length === 0) okButton.enabled = false; - } - } - } - } else { - all_photos.forEach(photo => { - photo.targetTip = []; - photo.state = "normal"; - photo.selected = false; - }); - - okButton.enabled = false; - } -} - -function updateSelectedTargets(playerid, selected) { - let i = 0; - const card = dashboard.getSelectedCard(); - const candidate = (!isNaN(card) && card !== -1) || typeof(card) === "string"; - const all_photos = []; - for (i = 0; i < playerNum; i++) { - all_photos.push(photos.itemAt(i)) - } - - if (selected) { - selected_targets.push(playerid); - } else { - selected_targets.splice(selected_targets.indexOf(playerid), 1); - } - - if (candidate) { - if (!selected) { - const remain_targets = []; - selected_targets.forEach(id => { - const photo = getPhoto(id); - const ret = lcall("CanUseCardToTarget", card, id, remain_targets, - JSON.stringify(roomScene.extra_data)); - let bool = ret; - if (roomScene.extra_data instanceof Object) { - const must = roomScene.extra_data.must_targets; - const included = roomScene.extra_data.include_targets; - const exclusive = roomScene.extra_data.exclusive_targets; - if (exclusive instanceof Array) { - if (exclusive.indexOf(id) === -1) bool = false; - } - if (must instanceof Array) { - if (must.filter((val) => { - return remain_targets.indexOf(val) === -1; - }).length !== 0 && must.indexOf(id) === -1) bool = false; - } - if (included instanceof Array) { - if (included.filter((val) => { - return remain_targets.indexOf(val) !== -1; - }).length === 0 && included.indexOf(id) === -1) bool = false; - } - } - if (bool) { - remain_targets.push(id); - } else { - photo.selected = false; - } - }) - selected_targets = remain_targets; - } - - roomScene.resetPrompt(); // update prompt due to selected_targets - const prompt = lcall("ActiveSkillPrompt", - dashboard.pending_skill !== "" ? dashboard.pending_skill: lcall("GetCardSkill", card), - dashboard.pending_skill !== "" ? dashboard.pendings : card, - selected_targets); - if (prompt !== "") { - roomScene.setPrompt(Util.processPrompt(prompt)); - } - - all_photos.forEach(photo => { - const id = photo.playerid; - const ret = lcall("CanUseCardToTarget", card, id, selected_targets, - JSON.stringify(roomScene.extra_data)); - - let tipText = lcall("GetUseCardTargetTip", card, id, selected_targets, - ret, JSON.stringify(roomScene.extra_data)); - if (tipText) { - photo.targetTip = tipText; - } else { - photo.targetTip = []; - } - - if (photo.selected) return; - photo.selectable = ret; - if (roomScene.extra_data instanceof Object) { - const must = roomScene.extra_data.must_targets; - const included = roomScene.extra_data.include_targets; - const exclusive = roomScene.extra_data.exclusive_targets; - if (exclusive instanceof Array) { - if (exclusive.indexOf(id) === -1) photo.selectable = false; - } - if (must instanceof Array) { - if (must.filter((val) => { - return selected_targets.indexOf(val) === -1; - }).length !== 0 && must.indexOf(id) === -1) photo.selectable = false; - } - if (included instanceof Array) { - if (included.filter((val) => { - return selected_targets.indexOf(val) !== -1; - }).length === 0 && included.indexOf(id) === -1) - photo.selectable = false; - } - } - }) - - okButton.enabled = lcall("CardFeasible", card, selected_targets); - if (okButton.enabled && roomScene.state === "responding") { - okButton.enabled = - lcall("CardFitPattern", card, roomScene.responding_card) && - (roomScene.autoPending || !lcall("CardProhibitedUse", card)); - } else if (okButton.enabled && roomScene.state === "playing") { - okButton.enabled = lcall("CanUseCard", card, Self.id, - JSON.stringify(roomScene.extra_data)); - } - if (okButton.enabled) { - if (roomScene.extra_data instanceof Object) { - const must = roomScene.extra_data.must_targets; - const included = roomScene.extra_data.include_targets; - if (must instanceof Array) { - if (must.filter((val) => { - return selected_targets.indexOf(val) === -1; - }).length !== 0) okButton.enabled = false; - } - if (included instanceof Array) { - if (included.filter((val) => { - return selected_targets.indexOf(val) !== -1; - }).length === 0) okButton.enabled = false; - } - } - } - } else { - all_photos.forEach(photo => { - photo.targetTip = []; - photo.state = "normal"; - photo.selected = false; - }); - - okButton.enabled = false; - } -} -*/ - callbacks["RemovePlayer"] = (data) => { // jsonData: int uid const uid = data[0]; @@ -1136,7 +832,7 @@ callbacks["AskForGeneral"] = (data) => { const convert = data[2]; const heg = data[3]; roomScene.setPrompt(luatr("#AskForGeneral"), true); - roomScene.state = "replying"; + roomScene.state = "active"; roomScene.popupBox.sourceComponent = Qt.createComponent("../RoomElement/ChooseGeneralBox.qml"); const box = roomScene.popupBox.item; @@ -1157,7 +853,7 @@ callbacks["AskForSkillInvoke"] = (data) => { const prompt = data[1]; roomScene.promptText = prompt ? processPrompt(prompt) : luatr("#AskForSkillInvoke").arg(luatr(skill)); - // roomScene.state = "replying"; + // roomScene.state = "active"; // roomScene.okCancel.visible = true; // roomScene.okButton.enabled = true; // roomScene.cancelButton.enabled = true; @@ -1165,7 +861,7 @@ callbacks["AskForSkillInvoke"] = (data) => { } callbacks["AskForArrangeCards"] = (data) => { - roomScene.state = "replying"; + roomScene.state = "active"; roomScene.popupBox.sourceComponent = Qt.createComponent("../RoomElement/ArrangeCardsBox.qml"); const box = roomScene.popupBox.item; @@ -1196,7 +892,7 @@ callbacks["AskForGuanxing"] = (data) => { const top_area_name = data.top_area_name; const bottom_area_name = data.bottom_area_name; const prompt = data.prompt; - roomScene.state = "replying"; + roomScene.state = "active"; roomScene.popupBox.sourceComponent = Qt.createComponent("../RoomElement/GuanxingBox.qml"); const box = roomScene.popupBox.item; @@ -1232,7 +928,7 @@ callbacks["AskForExchange"] = (data) => { const cards_name = []; const capacities = []; const limits = []; - roomScene.state = "replying"; + roomScene.state = "active"; roomScene.popupBox.sourceComponent = Qt.createComponent("../RoomElement/GuanxingBox.qml"); let for_i = 0; @@ -1271,7 +967,7 @@ callbacks["AskForChoice"] = (data) => { } else { roomScene.setPrompt(processPrompt(prompt), true); } - roomScene.state = "replying"; + roomScene.state = "active"; let qmlSrc; if (!detailed) { qmlSrc = "../RoomElement/ChoiceBox.qml"; @@ -1305,7 +1001,7 @@ callbacks["AskForChoices"] = (data) => { } else { roomScene.setPrompt(processPrompt(prompt), true); } - roomScene.state = "replying"; + roomScene.state = "active"; let qmlSrc; if (!detailed) { qmlSrc = "../RoomElement/CheckBox.qml"; @@ -1340,7 +1036,7 @@ callbacks["AskForCardChosen"] = (data) => { } else { roomScene.setPrompt(processPrompt(prompt), true); } - roomScene.state = "replying"; + roomScene.state = "active"; roomScene.popupBox.sourceComponent = Qt.createComponent("../RoomElement/PlayerCardBox.qml"); @@ -1372,7 +1068,7 @@ callbacks["AskForCardsChosen"] = (data) => { roomScene.setPrompt(processPrompt(prompt), true); } - roomScene.state = "replying"; + roomScene.state = "active"; roomScene.popupBox.sourceComponent = Qt.createComponent("../RoomElement/PlayerCardBox.qml"); const box = roomScene.popupBox.item; @@ -1397,7 +1093,7 @@ callbacks["AskForCardsChosen"] = (data) => { callbacks["AskForPoxi"] = (dat) => { const { type, data, extra_data, cancelable } = dat; - roomScene.state = "replying"; + roomScene.state = "active"; roomScene.popupBox.sourceComponent = Qt.createComponent("../RoomElement/PoxiBox.qml"); const box = roomScene.popupBox.item; @@ -1423,7 +1119,7 @@ callbacks["AskForPoxi"] = (dat) => { callbacks["AskForMoveCardInBoard"] = (data) => { const { cards, cardsPosition, generalNames, playerIds } = data; - roomScene.state = "replying"; + roomScene.state = "active"; roomScene.popupBox.sourceComponent = Qt.createComponent("../RoomElement/MoveCardInBoardBox.qml"); @@ -1532,15 +1228,6 @@ callbacks["AskForUseCard"] = (data) => { const prompt = data[2]; const extra_data = data[4]; const disabledSkillNames = data[5]; - if (extra_data != null) { - if (extra_data.effectTo !== Self.id && - roomScene.skippedUseEventId.find(id => id === extra_data.useEventId)) { - // doCancelButton(); - return; - } else { - roomScene.extra_data = extra_data; - } - } if (prompt === "") { roomScene.promptText = luatr("#AskForUseCard") @@ -1549,6 +1236,15 @@ callbacks["AskForUseCard"] = (data) => { roomScene.setPrompt(processPrompt(prompt), true); } roomScene.state = "active"; + if (extra_data != null) { + if (extra_data.effectTo !== Self.id && + roomScene.skippedUseEventId.find(id => id === extra_data.useEventId)) { + lcall("UpdateRequestUI", "Button", "Cancel"); + return; + } else { + roomScene.extra_data = extra_data; + } + } // roomScene.responding_card = pattern; // roomScene.respond_play = false; // disabledSkillNames && (dashboard.disabledSkillNames = disabledSkillNames); @@ -1763,7 +1459,7 @@ callbacks["FillAG"] = (data) => { } callbacks["AskForAG"] = (j) => { - roomScene.state = "replying"; + roomScene.state = "active"; roomScene.manualBox.item.interactive = true; } @@ -1783,7 +1479,7 @@ callbacks["CloseAG"] = () => roomScene.manualBox.item.close(); callbacks["CustomDialog"] = (data) => { const path = data.path; const dat = data.data; - roomScene.state = "replying"; + roomScene.state = "active"; roomScene.popupBox.source = AppPath + "/" + path; if (dat) { roomScene.popupBox.item.loadData(dat); @@ -1794,7 +1490,7 @@ callbacks["MiniGame"] = (data) => { const game = data.type; const dat = data.data; const gdata = lcall("GetMiniGame", game, Self.id, JSON.stringify(dat)); - roomScene.state = "replying"; + roomScene.state = "active"; roomScene.popupBox.source = AppPath + "/" + gdata.qml_path + ".qml"; if (dat) { roomScene.popupBox.item.loadData(dat); @@ -1859,39 +1555,20 @@ callbacks["ChangeSelf"] = (j) => { changeSelf(data); } -callbacks["AskForLuckCard"] = (j) => { - // jsonData: int time - if (config.observing || config.replaying) return; - const time = parseInt(j); - roomScene.setPrompt(luatr("#AskForLuckCard").arg(time), true); - roomScene.state = "replying"; - roomScene.extra_data = { - luckCard: true, - time: time, - }; - roomScene.okCancel.visible = true; - roomScene.okButton.enabled = true; - roomScene.cancelButton.enabled = true; -} - -//callbacks["CancelRequest"] = (jsonData) => { -// ClientInstance.replyToServer("", "__cancel") -//} - callbacks["UpdateRequestUI"] = (uiUpdate) => { if (uiUpdate["_prompt"]) roomScene.promptText = processPrompt(uiUpdate["_prompt"]); - if (uiUpdate._type == "RoomScene" || uiUpdate._type == "OKScene") { + if (uiUpdate._type == "Room") { // 需要判断是不是第一次收到这样的数据,可以通过state判断 // 因为是先收到Lua的数据,再切换状态的 // FIXME: 当然了 非常可能出现因为网络延迟过大导致在active状态收到新Request的情况! - if (roomScene.state === "notactive") { - okCancel.visible = true; - okButton.enabled = false; - cancelButton.enabled = false; - // endPhaseButton.visible = true; - } + // if (roomScene.state === "notactive") { + // okCancel.visible = true; + // okButton.enabled = false; + // cancelButton.enabled = false; + // // endPhaseButton.visible = true; + // } roomScene.applyChange(uiUpdate); } } diff --git a/Fk/RoomElement/HandcardArea.qml b/Fk/RoomElement/HandcardArea.qml index 7293686d..f8adab75 100644 --- a/Fk/RoomElement/HandcardArea.qml +++ b/Fk/RoomElement/HandcardArea.qml @@ -35,6 +35,7 @@ Item { card.autoBack = true; card.draggable = lcall("CanSortHandcards", Self.id); card.selectable = false; + card.clicked.connect(selectCard); card.clicked.connect(adjustCards); card.released.connect(updateCardReleased); card.xChanged.connect(updateCardDragging); @@ -48,6 +49,7 @@ Item { card = result[i]; card.draggable = false; card.selectable = false; + card.clicked.connect(selectCard); card.selectedChanged.disconnect(adjustCards); card.released.disconnect(updateCardReleased); card.xChanged.disconnect(updateCardDragging); @@ -125,7 +127,7 @@ Item { } function selectCard(card) { - cardSelected(card.cid, card.selected); + if (card.selectable) cardSelected(card.cid, card.selected); adjustCards(); } diff --git a/src/client/client.h b/src/client/client.h index db362d19..08e8ee27 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -36,6 +36,8 @@ public: bool isConsoleStart() const; void startWatchFiles(); + + Router *getRouter() const { return router; } signals: void error_message(const QString &msg); diff --git a/src/network/router.cpp b/src/network/router.cpp index 2475ba60..f599c11b 100644 --- a/src/network/router.cpp +++ b/src/network/router.cpp @@ -57,7 +57,7 @@ void Router::setReplyReadySemaphore(QSemaphore *semaphore) { } void Router::request(int type, const QString &command, const QString &jsonData, - int timeout) { + int timeout, qint64 timestamp) { // In case a request is called without a following waitForReply call if (replyReadySemaphore.available() > 0) replyReadySemaphore.acquire(replyReadySemaphore.available()); @@ -78,6 +78,7 @@ void Router::request(int type, const QString &command, const QString &jsonData, body << command; body << jsonData; body << timeout; + body << (timestamp <= 0 ? requestStartTime.toMSecsSinceEpoch() : timestamp); emit messageReady(JsonArray2Bytes(body)); } @@ -165,10 +166,12 @@ void Router::handlePacket(const QByteArray &rawPacket) { } else if (type & TYPE_REQUEST) { this->requestId = requestId; this->requestTimeout = packet[4].toInt(); + this->requestTimestamp = packet[5].toInteger(); if (type & DEST_CLIENT) { #ifndef FK_SERVER_ONLY - qobject_cast(parent())->callLua(command, jsonData, true); + auto client = qobject_cast(parent()); + client->callLua(command, jsonData, true); #endif } else { // requesting server is not allowed diff --git a/src/network/router.h b/src/network/router.h index a21a1b5a..e7429100 100644 --- a/src/network/router.h +++ b/src/network/router.h @@ -37,7 +37,7 @@ public: void setReplyReadySemaphore(QSemaphore *semaphore); void request(int type, const QString &command, - const QString &jsonData, int timeout); + const QString &jsonData, int timeout, qint64 timestamp = -1); void reply(int type, const QString &command, const QString &jsonData); void notify(int type, const QString &command, const QString &jsonData); @@ -48,6 +48,9 @@ public: QString waitForReply(int timeout); + int getRequestId() const { return requestId; } + qint64 getRequestTimestamp() { return requestTimestamp; } + signals: void messageReady(const QByteArray &message); void unknownPacket(const QByteArray &packet); @@ -60,11 +63,12 @@ private: ClientSocket *socket; RouterType type; - // For sender + // For client side int requestId; int requestTimeout; + qint64 requestTimestamp; - // For receiver + // For server side QDateTime requestStartTime; QMutex replyMutex; int expectedReplyId; diff --git a/src/server/serverplayer.cpp b/src/server/serverplayer.cpp index 902c3d34..be5175ff 100644 --- a/src/server/serverplayer.cpp +++ b/src/server/serverplayer.cpp @@ -69,11 +69,11 @@ void ServerPlayer::setRoom(RoomBase *room) { this->room = room; } void ServerPlayer::speak(const QString &message) { ; } void ServerPlayer::doRequest(const QString &command, const QString &jsonData, - int timeout) { + int timeout, qint64 timestamp) { if (getState() != Player::Online) return; int type = Router::TYPE_REQUEST | Router::SRC_SERVER | Router::DEST_CLIENT; - router->request(type, command, jsonData, timeout); + router->request(type, command, jsonData, timeout, timestamp); } void ServerPlayer::abortRequest() { router->abortRequest(); } diff --git a/src/server/serverplayer.h b/src/server/serverplayer.h index 6960bf77..2ef4a1ed 100644 --- a/src/server/serverplayer.h +++ b/src/server/serverplayer.h @@ -28,7 +28,7 @@ public: void speak(const QString &message); void doRequest(const QString &command, - const QString &jsonData, int timeout = -1); + const QString &jsonData, int timeout = -1, qint64 timestamp = -1); void abortRequest(); QString waitForReply(int timeout); void doNotify(const QString &command, const QString &jsonData); diff --git a/src/swig/freekill-nogui.i b/src/swig/freekill-nogui.i index b7ebd97a..1431f61c 100644 --- a/src/swig/freekill-nogui.i +++ b/src/swig/freekill-nogui.i @@ -2,6 +2,8 @@ %module fk +%include "naturalvar.i" + %{ #include "server/server.h" #include "server/serverplayer.h" @@ -13,7 +15,6 @@ class ClientPlayer *Self = nullptr; %} -%include "naturalvar.i" %include "qt.i" %include "qml-nogui.i" %include "player.i" diff --git a/src/swig/freekill.i b/src/swig/freekill.i index 962f9014..83ee1fb3 100644 --- a/src/swig/freekill.i +++ b/src/swig/freekill.i @@ -2,6 +2,8 @@ %module fk +%include "naturalvar.i" + %{ #include "client/client.h" #include "server/server.h" @@ -15,7 +17,6 @@ const char *FK_VER = FK_VERSION; %} -%include "naturalvar.i" %include "qt.i" %include "player.i" %include "client.i" diff --git a/src/swig/naturalvar.i b/src/swig/naturalvar.i index f83a4f84..d6d39129 100644 --- a/src/swig/naturalvar.i +++ b/src/swig/naturalvar.i @@ -41,6 +41,7 @@ SWIG_arg ++; %typemap(out) QString %{ + // FIXME: 这里针对高频出现的字符串减少toUtf8调用避免创建新的bytearray... if ($1.isEmpty()) { lua_pushstring(L, ""); } else if ($1 == "__notready") { @@ -52,13 +53,11 @@ SWIG_arg ++; %} // const QString & -%typemap(arginit) QString const & - "QString $1_str;" -%typemap(in, checkfn = "lua_isstring") QString const & +%typemap(in, checkfn = "lua_isstring") QString const & ($*1_ltype temp) %{ - $1_str = QString::fromUtf8(lua_tostring(L, $input)); - $1 = &$1_str; + temp = QString::fromUtf8(lua_tostring(L, $input)); + $1 = &temp; %} %typemap(out) QString const & @@ -73,6 +72,11 @@ SWIG_arg ++; SWIG_arg++; %} +// 解决函数重载中类型检测问题 +%typecheck(SWIG_TYPECHECK_STRING) QString, QString const& { + $1 = lua_isstring(L,$input); +} + // QStringList %naturalvar QStringList; diff --git a/src/swig/server.i b/src/swig/server.i index 97d546b5..c4bb2013 100644 --- a/src/swig/server.i +++ b/src/swig/server.i @@ -79,7 +79,7 @@ void Scheduler::tellThreadToLua() class ServerPlayer : public Player { public: void doRequest(const QString &command, - const QString &json_data, int timeout); + const QString &json_data, int timeout, long long timestamp = -1); QString waitForReply(int timeout); void doNotify(const QString &command, const QString &json_data); diff --git a/src/ui/qmlbackend.cpp b/src/ui/qmlbackend.cpp index 461e8a41..0657b07b 100644 --- a/src/ui/qmlbackend.cpp +++ b/src/ui/qmlbackend.cpp @@ -1,6 +1,8 @@ // SPDX-License-Identifier: GPL-3.0-or-later #include "ui/qmlbackend.h" +#include +#include #ifndef FK_SERVER_ONLY #include @@ -647,4 +649,13 @@ void QmlBackend::controlReplayer(QString type) { } } +QJsonObject QmlBackend::getRequestData() const { + auto obj = QJsonObject(); + auto router = ClientInstance->getRouter(); + obj["id"] = router->getRequestId(); + obj["timeout"] = router->getTimeout(); + obj["timestamp"] = router->getRequestTimestamp(); + return obj; +} + #endif diff --git a/src/ui/qmlbackend.h b/src/ui/qmlbackend.h index 2f3e949c..c23cabf2 100644 --- a/src/ui/qmlbackend.h +++ b/src/ui/qmlbackend.h @@ -80,6 +80,8 @@ public: void setReplayer(Replayer *rep); Q_INVOKABLE void controlReplayer(QString type); + Q_INVOKABLE QJsonObject getRequestData() const; + signals: void notifyUI(const QString &command, const QVariant &data); void dialog(const QString &type, const QString &text, const QString &orig = QString());