UI rewrite2 (#371)
Some checks failed
Check Whitespace and New Line / check (push) Has been cancelled
Deploy Sphinx documentation to Pages / pages (push) Has been cancelled

基本上能玩了

---------

Co-authored-by: YoumuKon <38815081+YoumuKon@users.noreply.github.com>
This commit is contained in:
notify 2024-10-13 10:38:55 +08:00 committed by GitHub
parent fa8335a330
commit 951a9a0497
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 100 additions and 433 deletions

View File

@ -314,15 +314,15 @@ Item {
state: "notactive" state: "notactive"
transitions: [ transitions: [
Transition { Transition {
from: "active"; to: "notactive" from: "*"; to: "notactive"
ScriptAction { ScriptAction {
script: { script: {
skillInteraction.sourceComponent = undefined; skillInteraction.sourceComponent = undefined;
promptText = ""; promptText = "";
progress.visible = false;
okCancel.visible = false; okCancel.visible = false;
endPhaseButton.visible = false; endPhaseButton.visible = false;
progress.visible = false; progress.visible = false;
extra_data = {};
dashboard.disableAllCards(); dashboard.disableAllCards();
dashboard.disableSkills(); dashboard.disableSkills();
@ -348,6 +348,12 @@ Item {
from: "notactive"; to: "active" from: "notactive"; to: "active"
ScriptAction { ScriptAction {
script: { 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; progress.visible = true;
} }
} }
@ -402,7 +408,6 @@ Item {
sealedSlots: JSON.parse(model.sealedSlots) sealedSlots: JSON.parse(model.sealedSlots)
onSelectedChanged: { onSelectedChanged: {
// Logic.updateSelectedTargets(playerid, selected);
if ( state === "candidate" ) lcall("UpdateRequestUI", "Photo", playerid, "click", { selected } ); if ( state === "candidate" ) lcall("UpdateRequestUI", "Photo", playerid, "click", { selected } );
} }
@ -455,6 +460,7 @@ Item {
onClicked: roomScene.startCheat("../RoomElement/ChooseHandcard"); onClicked: roomScene.startCheat("../RoomElement/ChooseHandcard");
} }
MetroButton { MetroButton {
id: revertSelectionBtn
text: luatr("Revert Selection") text: luatr("Revert Selection")
textFont.pixelSize: 28 textFont.pixelSize: 28
enabled: dashboard.pending_skill !== "" enabled: dashboard.pending_skill !== ""
@ -542,29 +548,6 @@ Item {
width: roomScene.width - dashboardBtn.width width: roomScene.width - dashboardBtn.width
anchors.top: roomArea.bottom anchors.top: roomArea.bottom
anchors.left: dashboardBtn.right 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 { Rectangle {
@ -684,6 +667,7 @@ Item {
} }
NumberAnimation on value { NumberAnimation on value {
id: progressAnim
running: progress.visible running: progress.visible
from: 100.0 from: 100.0
to: 0.0 to: 0.0
@ -703,7 +687,7 @@ Item {
color: "#88EEEEEE" color: "#88EEEEEE"
radius: 8 radius: 8
visible: { visible: {
if (roomScene.state !== "playing") { if (roomScene.state !== "active") {
return false; return false;
} }
if (!specialCardSkills) { if (!specialCardSkills) {
@ -727,25 +711,7 @@ Item {
text: luatr(modelData) text: luatr(modelData)
checked: index === 0 checked: index === 0
onCheckedChanged: { onCheckedChanged: {
roomScene.resetPrompt(); lcall("UpdateRequestUI", "SpecialSkills", "1", "click", modelData);
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));
}
} }
} }
} }
@ -774,7 +740,7 @@ Item {
&& !skippedUseEventId.find(id => id === extra_data.useEventId) && !skippedUseEventId.find(id => id === extra_data.useEventId)
onClicked: { onClicked: {
skippedUseEventId.push(extra_data.useEventId); skippedUseEventId.push(extra_data.useEventId);
// Logic.doCancelButton(); lcall("UpdateRequestUI", "Button", "Cancel");
} }
} }
@ -1112,21 +1078,6 @@ Item {
onActivated: menuContainer.open(); 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) { function addToChat(pid, raw, msg) {
if (raw.type === 1) return; if (raw.type === 1) return;
const photo = Logic.getPhoto(pid); const photo = Logic.getPhoto(pid);
@ -1336,7 +1287,6 @@ Item {
} }
function applyChange(uiUpdate) { function applyChange(uiUpdate) {
//console.log(JSON.stringify(uiUpdate))
uiUpdate["_delete"]?.forEach(data => { uiUpdate["_delete"]?.forEach(data => {
if (data.type == "Interaction") { if (data.type == "Interaction") {
skillInteraction.sourceComponent = undefined; skillInteraction.sourceComponent = undefined;
@ -1381,6 +1331,11 @@ Item {
} }
}); });
const sskilldata = uiUpdate["SpecialSkills"]?.[0]
if (sskilldata) {
specialCardSkills.model = sskilldata?.skills ?? [];
}
dashboard.applyChange(uiUpdate); dashboard.applyChange(uiUpdate);
const pdatas = uiUpdate["Photo"]; const pdatas = uiUpdate["Photo"];
pdatas?.forEach(pdata => { pdatas?.forEach(pdata => {
@ -1390,6 +1345,11 @@ Item {
photo.selected = pdata.selected; photo.selected = pdata.selected;
}) })
const buttons = uiUpdate["Button"]; const buttons = uiUpdate["Button"];
if (buttons) {
okCancel.visible = true;
okButton.enabled = false;
cancelButton.enabled = false;
}
buttons?.forEach(bdata => { buttons?.forEach(bdata => {
switch (bdata.id) { switch (bdata.id) {
case "OK": case "OK":

View File

@ -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) { function replyToServer(jsonData) {
ClientInstance.replyToServer("", jsonData); ClientInstance.replyToServer("", jsonData);
if (!mainWindow.is_pending) { 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) => { callbacks["RemovePlayer"] = (data) => {
// jsonData: int uid // jsonData: int uid
const uid = data[0]; const uid = data[0];
@ -1136,7 +832,7 @@ callbacks["AskForGeneral"] = (data) => {
const convert = data[2]; const convert = data[2];
const heg = data[3]; const heg = data[3];
roomScene.setPrompt(luatr("#AskForGeneral"), true); roomScene.setPrompt(luatr("#AskForGeneral"), true);
roomScene.state = "replying"; roomScene.state = "active";
roomScene.popupBox.sourceComponent = roomScene.popupBox.sourceComponent =
Qt.createComponent("../RoomElement/ChooseGeneralBox.qml"); Qt.createComponent("../RoomElement/ChooseGeneralBox.qml");
const box = roomScene.popupBox.item; const box = roomScene.popupBox.item;
@ -1157,7 +853,7 @@ callbacks["AskForSkillInvoke"] = (data) => {
const prompt = data[1]; const prompt = data[1];
roomScene.promptText = prompt ? processPrompt(prompt) roomScene.promptText = prompt ? processPrompt(prompt)
: luatr("#AskForSkillInvoke").arg(luatr(skill)); : luatr("#AskForSkillInvoke").arg(luatr(skill));
// roomScene.state = "replying"; // roomScene.state = "active";
// roomScene.okCancel.visible = true; // roomScene.okCancel.visible = true;
// roomScene.okButton.enabled = true; // roomScene.okButton.enabled = true;
// roomScene.cancelButton.enabled = true; // roomScene.cancelButton.enabled = true;
@ -1165,7 +861,7 @@ callbacks["AskForSkillInvoke"] = (data) => {
} }
callbacks["AskForArrangeCards"] = (data) => { callbacks["AskForArrangeCards"] = (data) => {
roomScene.state = "replying"; roomScene.state = "active";
roomScene.popupBox.sourceComponent = roomScene.popupBox.sourceComponent =
Qt.createComponent("../RoomElement/ArrangeCardsBox.qml"); Qt.createComponent("../RoomElement/ArrangeCardsBox.qml");
const box = roomScene.popupBox.item; const box = roomScene.popupBox.item;
@ -1196,7 +892,7 @@ callbacks["AskForGuanxing"] = (data) => {
const top_area_name = data.top_area_name; const top_area_name = data.top_area_name;
const bottom_area_name = data.bottom_area_name; const bottom_area_name = data.bottom_area_name;
const prompt = data.prompt; const prompt = data.prompt;
roomScene.state = "replying"; roomScene.state = "active";
roomScene.popupBox.sourceComponent = roomScene.popupBox.sourceComponent =
Qt.createComponent("../RoomElement/GuanxingBox.qml"); Qt.createComponent("../RoomElement/GuanxingBox.qml");
const box = roomScene.popupBox.item; const box = roomScene.popupBox.item;
@ -1232,7 +928,7 @@ callbacks["AskForExchange"] = (data) => {
const cards_name = []; const cards_name = [];
const capacities = []; const capacities = [];
const limits = []; const limits = [];
roomScene.state = "replying"; roomScene.state = "active";
roomScene.popupBox.sourceComponent = roomScene.popupBox.sourceComponent =
Qt.createComponent("../RoomElement/GuanxingBox.qml"); Qt.createComponent("../RoomElement/GuanxingBox.qml");
let for_i = 0; let for_i = 0;
@ -1271,7 +967,7 @@ callbacks["AskForChoice"] = (data) => {
} else { } else {
roomScene.setPrompt(processPrompt(prompt), true); roomScene.setPrompt(processPrompt(prompt), true);
} }
roomScene.state = "replying"; roomScene.state = "active";
let qmlSrc; let qmlSrc;
if (!detailed) { if (!detailed) {
qmlSrc = "../RoomElement/ChoiceBox.qml"; qmlSrc = "../RoomElement/ChoiceBox.qml";
@ -1305,7 +1001,7 @@ callbacks["AskForChoices"] = (data) => {
} else { } else {
roomScene.setPrompt(processPrompt(prompt), true); roomScene.setPrompt(processPrompt(prompt), true);
} }
roomScene.state = "replying"; roomScene.state = "active";
let qmlSrc; let qmlSrc;
if (!detailed) { if (!detailed) {
qmlSrc = "../RoomElement/CheckBox.qml"; qmlSrc = "../RoomElement/CheckBox.qml";
@ -1340,7 +1036,7 @@ callbacks["AskForCardChosen"] = (data) => {
} else { } else {
roomScene.setPrompt(processPrompt(prompt), true); roomScene.setPrompt(processPrompt(prompt), true);
} }
roomScene.state = "replying"; roomScene.state = "active";
roomScene.popupBox.sourceComponent = roomScene.popupBox.sourceComponent =
Qt.createComponent("../RoomElement/PlayerCardBox.qml"); Qt.createComponent("../RoomElement/PlayerCardBox.qml");
@ -1372,7 +1068,7 @@ callbacks["AskForCardsChosen"] = (data) => {
roomScene.setPrompt(processPrompt(prompt), true); roomScene.setPrompt(processPrompt(prompt), true);
} }
roomScene.state = "replying"; roomScene.state = "active";
roomScene.popupBox.sourceComponent = roomScene.popupBox.sourceComponent =
Qt.createComponent("../RoomElement/PlayerCardBox.qml"); Qt.createComponent("../RoomElement/PlayerCardBox.qml");
const box = roomScene.popupBox.item; const box = roomScene.popupBox.item;
@ -1397,7 +1093,7 @@ callbacks["AskForCardsChosen"] = (data) => {
callbacks["AskForPoxi"] = (dat) => { callbacks["AskForPoxi"] = (dat) => {
const { type, data, extra_data, cancelable } = dat; const { type, data, extra_data, cancelable } = dat;
roomScene.state = "replying"; roomScene.state = "active";
roomScene.popupBox.sourceComponent = roomScene.popupBox.sourceComponent =
Qt.createComponent("../RoomElement/PoxiBox.qml"); Qt.createComponent("../RoomElement/PoxiBox.qml");
const box = roomScene.popupBox.item; const box = roomScene.popupBox.item;
@ -1423,7 +1119,7 @@ callbacks["AskForPoxi"] = (dat) => {
callbacks["AskForMoveCardInBoard"] = (data) => { callbacks["AskForMoveCardInBoard"] = (data) => {
const { cards, cardsPosition, generalNames, playerIds } = data; const { cards, cardsPosition, generalNames, playerIds } = data;
roomScene.state = "replying"; roomScene.state = "active";
roomScene.popupBox.sourceComponent = roomScene.popupBox.sourceComponent =
Qt.createComponent("../RoomElement/MoveCardInBoardBox.qml"); Qt.createComponent("../RoomElement/MoveCardInBoardBox.qml");
@ -1532,15 +1228,6 @@ callbacks["AskForUseCard"] = (data) => {
const prompt = data[2]; const prompt = data[2];
const extra_data = data[4]; const extra_data = data[4];
const disabledSkillNames = data[5]; 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 === "") { if (prompt === "") {
roomScene.promptText = luatr("#AskForUseCard") roomScene.promptText = luatr("#AskForUseCard")
@ -1549,6 +1236,15 @@ callbacks["AskForUseCard"] = (data) => {
roomScene.setPrompt(processPrompt(prompt), true); roomScene.setPrompt(processPrompt(prompt), true);
} }
roomScene.state = "active"; 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.responding_card = pattern;
// roomScene.respond_play = false; // roomScene.respond_play = false;
// disabledSkillNames && (dashboard.disabledSkillNames = disabledSkillNames); // disabledSkillNames && (dashboard.disabledSkillNames = disabledSkillNames);
@ -1763,7 +1459,7 @@ callbacks["FillAG"] = (data) => {
} }
callbacks["AskForAG"] = (j) => { callbacks["AskForAG"] = (j) => {
roomScene.state = "replying"; roomScene.state = "active";
roomScene.manualBox.item.interactive = true; roomScene.manualBox.item.interactive = true;
} }
@ -1783,7 +1479,7 @@ callbacks["CloseAG"] = () => roomScene.manualBox.item.close();
callbacks["CustomDialog"] = (data) => { callbacks["CustomDialog"] = (data) => {
const path = data.path; const path = data.path;
const dat = data.data; const dat = data.data;
roomScene.state = "replying"; roomScene.state = "active";
roomScene.popupBox.source = AppPath + "/" + path; roomScene.popupBox.source = AppPath + "/" + path;
if (dat) { if (dat) {
roomScene.popupBox.item.loadData(dat); roomScene.popupBox.item.loadData(dat);
@ -1794,7 +1490,7 @@ callbacks["MiniGame"] = (data) => {
const game = data.type; const game = data.type;
const dat = data.data; const dat = data.data;
const gdata = lcall("GetMiniGame", game, Self.id, JSON.stringify(dat)); const gdata = lcall("GetMiniGame", game, Self.id, JSON.stringify(dat));
roomScene.state = "replying"; roomScene.state = "active";
roomScene.popupBox.source = AppPath + "/" + gdata.qml_path + ".qml"; roomScene.popupBox.source = AppPath + "/" + gdata.qml_path + ".qml";
if (dat) { if (dat) {
roomScene.popupBox.item.loadData(dat); roomScene.popupBox.item.loadData(dat);
@ -1859,39 +1555,20 @@ callbacks["ChangeSelf"] = (j) => {
changeSelf(data); 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) => { callbacks["UpdateRequestUI"] = (uiUpdate) => {
if (uiUpdate["_prompt"]) if (uiUpdate["_prompt"])
roomScene.promptText = processPrompt(uiUpdate["_prompt"]); roomScene.promptText = processPrompt(uiUpdate["_prompt"]);
if (uiUpdate._type == "RoomScene" || uiUpdate._type == "OKScene") { if (uiUpdate._type == "Room") {
// 需要判断是不是第一次收到这样的数据可以通过state判断 // 需要判断是不是第一次收到这样的数据可以通过state判断
// 因为是先收到Lua的数据再切换状态的 // 因为是先收到Lua的数据再切换状态的
// FIXME: 当然了 非常可能出现因为网络延迟过大导致在active状态收到新Request的情况 // FIXME: 当然了 非常可能出现因为网络延迟过大导致在active状态收到新Request的情况
if (roomScene.state === "notactive") { // if (roomScene.state === "notactive") {
okCancel.visible = true; // okCancel.visible = true;
okButton.enabled = false; // okButton.enabled = false;
cancelButton.enabled = false; // cancelButton.enabled = false;
// endPhaseButton.visible = true; // // endPhaseButton.visible = true;
} // }
roomScene.applyChange(uiUpdate); roomScene.applyChange(uiUpdate);
} }
} }

View File

@ -35,6 +35,7 @@ Item {
card.autoBack = true; card.autoBack = true;
card.draggable = lcall("CanSortHandcards", Self.id); card.draggable = lcall("CanSortHandcards", Self.id);
card.selectable = false; card.selectable = false;
card.clicked.connect(selectCard);
card.clicked.connect(adjustCards); card.clicked.connect(adjustCards);
card.released.connect(updateCardReleased); card.released.connect(updateCardReleased);
card.xChanged.connect(updateCardDragging); card.xChanged.connect(updateCardDragging);
@ -48,6 +49,7 @@ Item {
card = result[i]; card = result[i];
card.draggable = false; card.draggable = false;
card.selectable = false; card.selectable = false;
card.clicked.connect(selectCard);
card.selectedChanged.disconnect(adjustCards); card.selectedChanged.disconnect(adjustCards);
card.released.disconnect(updateCardReleased); card.released.disconnect(updateCardReleased);
card.xChanged.disconnect(updateCardDragging); card.xChanged.disconnect(updateCardDragging);
@ -125,7 +127,7 @@ Item {
} }
function selectCard(card) { function selectCard(card) {
cardSelected(card.cid, card.selected); if (card.selectable) cardSelected(card.cid, card.selected);
adjustCards(); adjustCards();
} }

View File

@ -36,6 +36,8 @@ public:
bool isConsoleStart() const; bool isConsoleStart() const;
void startWatchFiles(); void startWatchFiles();
Router *getRouter() const { return router; }
signals: signals:
void error_message(const QString &msg); void error_message(const QString &msg);

View File

@ -57,7 +57,7 @@ void Router::setReplyReadySemaphore(QSemaphore *semaphore) {
} }
void Router::request(int type, const QString &command, const QString &jsonData, 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 // In case a request is called without a following waitForReply call
if (replyReadySemaphore.available() > 0) if (replyReadySemaphore.available() > 0)
replyReadySemaphore.acquire(replyReadySemaphore.available()); replyReadySemaphore.acquire(replyReadySemaphore.available());
@ -78,6 +78,7 @@ void Router::request(int type, const QString &command, const QString &jsonData,
body << command; body << command;
body << jsonData; body << jsonData;
body << timeout; body << timeout;
body << (timestamp <= 0 ? requestStartTime.toMSecsSinceEpoch() : timestamp);
emit messageReady(JsonArray2Bytes(body)); emit messageReady(JsonArray2Bytes(body));
} }
@ -165,10 +166,12 @@ void Router::handlePacket(const QByteArray &rawPacket) {
} else if (type & TYPE_REQUEST) { } else if (type & TYPE_REQUEST) {
this->requestId = requestId; this->requestId = requestId;
this->requestTimeout = packet[4].toInt(); this->requestTimeout = packet[4].toInt();
this->requestTimestamp = packet[5].toInteger();
if (type & DEST_CLIENT) { if (type & DEST_CLIENT) {
#ifndef FK_SERVER_ONLY #ifndef FK_SERVER_ONLY
qobject_cast<Client *>(parent())->callLua(command, jsonData, true); auto client = qobject_cast<Client *>(parent());
client->callLua(command, jsonData, true);
#endif #endif
} else { } else {
// requesting server is not allowed // requesting server is not allowed

View File

@ -37,7 +37,7 @@ public:
void setReplyReadySemaphore(QSemaphore *semaphore); void setReplyReadySemaphore(QSemaphore *semaphore);
void request(int type, const QString &command, 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 reply(int type, const QString &command, const QString &jsonData);
void notify(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); QString waitForReply(int timeout);
int getRequestId() const { return requestId; }
qint64 getRequestTimestamp() { return requestTimestamp; }
signals: signals:
void messageReady(const QByteArray &message); void messageReady(const QByteArray &message);
void unknownPacket(const QByteArray &packet); void unknownPacket(const QByteArray &packet);
@ -60,11 +63,12 @@ private:
ClientSocket *socket; ClientSocket *socket;
RouterType type; RouterType type;
// For sender // For client side
int requestId; int requestId;
int requestTimeout; int requestTimeout;
qint64 requestTimestamp;
// For receiver // For server side
QDateTime requestStartTime; QDateTime requestStartTime;
QMutex replyMutex; QMutex replyMutex;
int expectedReplyId; int expectedReplyId;

View File

@ -69,11 +69,11 @@ void ServerPlayer::setRoom(RoomBase *room) { this->room = room; }
void ServerPlayer::speak(const QString &message) { ; } void ServerPlayer::speak(const QString &message) { ; }
void ServerPlayer::doRequest(const QString &command, const QString &jsonData, void ServerPlayer::doRequest(const QString &command, const QString &jsonData,
int timeout) { int timeout, qint64 timestamp) {
if (getState() != Player::Online) if (getState() != Player::Online)
return; return;
int type = Router::TYPE_REQUEST | Router::SRC_SERVER | Router::DEST_CLIENT; 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(); } void ServerPlayer::abortRequest() { router->abortRequest(); }

View File

@ -28,7 +28,7 @@ public:
void speak(const QString &message); void speak(const QString &message);
void doRequest(const QString &command, void doRequest(const QString &command,
const QString &jsonData, int timeout = -1); const QString &jsonData, int timeout = -1, qint64 timestamp = -1);
void abortRequest(); void abortRequest();
QString waitForReply(int timeout); QString waitForReply(int timeout);
void doNotify(const QString &command, const QString &jsonData); void doNotify(const QString &command, const QString &jsonData);

View File

@ -2,6 +2,8 @@
%module fk %module fk
%include "naturalvar.i"
%{ %{
#include "server/server.h" #include "server/server.h"
#include "server/serverplayer.h" #include "server/serverplayer.h"
@ -13,7 +15,6 @@
class ClientPlayer *Self = nullptr; class ClientPlayer *Self = nullptr;
%} %}
%include "naturalvar.i"
%include "qt.i" %include "qt.i"
%include "qml-nogui.i" %include "qml-nogui.i"
%include "player.i" %include "player.i"

View File

@ -2,6 +2,8 @@
%module fk %module fk
%include "naturalvar.i"
%{ %{
#include "client/client.h" #include "client/client.h"
#include "server/server.h" #include "server/server.h"
@ -15,7 +17,6 @@
const char *FK_VER = FK_VERSION; const char *FK_VER = FK_VERSION;
%} %}
%include "naturalvar.i"
%include "qt.i" %include "qt.i"
%include "player.i" %include "player.i"
%include "client.i" %include "client.i"

View File

@ -41,6 +41,7 @@ SWIG_arg ++;
%typemap(out) QString %typemap(out) QString
%{ %{
// FIXME: 这里针对高频出现的字符串减少toUtf8调用避免创建新的bytearray...
if ($1.isEmpty()) { if ($1.isEmpty()) {
lua_pushstring(L, ""); lua_pushstring(L, "");
} else if ($1 == "__notready") { } else if ($1 == "__notready") {
@ -52,13 +53,11 @@ SWIG_arg ++;
%} %}
// const QString & // 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)); temp = QString::fromUtf8(lua_tostring(L, $input));
$1 = &$1_str; $1 = &temp;
%} %}
%typemap(out) QString const & %typemap(out) QString const &
@ -73,6 +72,11 @@ SWIG_arg ++;
SWIG_arg++; SWIG_arg++;
%} %}
// 解决函数重载中类型检测问题
%typecheck(SWIG_TYPECHECK_STRING) QString, QString const& {
$1 = lua_isstring(L,$input);
}
// QStringList // QStringList
%naturalvar QStringList; %naturalvar QStringList;

View File

@ -79,7 +79,7 @@ void Scheduler::tellThreadToLua()
class ServerPlayer : public Player { class ServerPlayer : public Player {
public: public:
void doRequest(const QString &command, 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); QString waitForReply(int timeout);
void doNotify(const QString &command, const QString &json_data); void doNotify(const QString &command, const QString &json_data);

View File

@ -1,6 +1,8 @@
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
#include "ui/qmlbackend.h" #include "ui/qmlbackend.h"
#include <qjsondocument.h>
#include <qjsonobject.h>
#ifndef FK_SERVER_ONLY #ifndef FK_SERVER_ONLY
#include <QAudioOutput> #include <QAudioOutput>
@ -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 #endif

View File

@ -80,6 +80,8 @@ public:
void setReplayer(Replayer *rep); void setReplayer(Replayer *rep);
Q_INVOKABLE void controlReplayer(QString type); Q_INVOKABLE void controlReplayer(QString type);
Q_INVOKABLE QJsonObject getRequestData() const;
signals: signals:
void notifyUI(const QString &command, const QVariant &data); void notifyUI(const QString &command, const QVariant &data);
void dialog(const QString &type, const QString &text, const QString &orig = QString()); void dialog(const QString &type, const QString &text, const QString &orig = QString());