From 584f81b93154313a3856112400b7df98e0eb2632 Mon Sep 17 00:00:00 2001 From: Benjamin Auder Date: Mon, 9 Mar 2020 15:28:19 +0100 Subject: [PATCH] Fix rematch process --- client/src/views/Game.vue | 138 ++++++++++++++++++++++---------------- client/src/views/Hall.vue | 12 +++- server/models/Game.js | 10 +-- server/routes/games.js | 2 +- server/sockets.js | 2 +- 5 files changed, 101 insertions(+), 63 deletions(-) diff --git a/client/src/views/Game.vue b/client/src/views/Game.vue index f24430b8..024847ce 100644 --- a/client/src/views/Game.vue +++ b/client/src/views/Game.vue @@ -163,6 +163,7 @@ export default { drawOffer: "", infoMessage: "", rematchOffer: "", + lastateAsked: false, people: {}, //players + observers onMygames: [], //opponents (or me) on "MyGames" page lastate: undefined, //used if opponent send lastate before game is ready @@ -268,6 +269,7 @@ export default { this.virtualClocks = [[0,0], [0,0]]; this.vr = null; this.drawOffer = ""; + this.lastateAsked = false; this.rematchOffer = ""; this.onMygames = []; this.lastate = undefined; @@ -396,6 +398,9 @@ export default { this.$set(this.game, "chats", []); } }, + getGameType: function(game) { + return game.cadence.indexOf("d") >= 0 ? "corr" : "live"; + }, // Notify turn after a new move (to opponent and me on MyGames page) notifyTurn: function(sid) { const player = this.people[sid]; @@ -596,31 +601,9 @@ export default { break; case "asklastate": // Sending informative last state if I played a move or score != "*" - if ( - (this.game.moves.length > 0 && this.vr.turn != this.game.mycolor) || - this.game.score != "*" || - this.drawOffer == "sent" || - this.rematchOffer == "sent" - ) { - // Send our "last state" informations to opponent - const L = this.game.moves.length; - const myIdx = ["w", "b"].indexOf(this.game.mycolor); - const myLastate = { - lastMove: L > 0 ? this.game.moves[L - 1] : undefined, - clock: this.game.clocks[myIdx], - // Since we played a move (or abort or resign), - // only drawOffer=="sent" is possible - drawSent: this.drawOffer == "sent", - rematchSent: this.rematchOffer == "sent", - score: this.game.score, - score: this.game.scoreMsg, - movesCount: L, - initime: this.game.initime[1 - myIdx] //relevant only if I played - }; - this.send("lastate", { data: myLastate, target: data.from }); - } else { - this.send("lastate", { data: {nothing: true}, target: data.from }); - } + // If the game or moves aren't loaded yet, delay the sending: + if (!this.game || !this.game.moves) this.lastateAsked = true; + else this.sendLastate(data.from); break; case "lastate": { // Got opponent infos about last move @@ -711,9 +694,15 @@ export default { case "newgame": { // A game started, redirect if I'm playing in const gameInfo = data.data; + const gameType = this.getGameType(gameInfo); if ( - gameInfo.players.some(p => - p.sid == this.st.user.sid || p.uid == this.st.user.id) + gameType == "live" && + gameInfo.players.some(p => p.sid == this.st.user.sid) + ) { + this.addAndGotoLiveGame(gameInfo); + } else if ( + gameType == "corr" && + gameInfo.players.some(p => p.uid == this.st.user.id) ) { this.$router.push("/game/" + gameInfo.id); } else { @@ -766,6 +755,33 @@ export default { } ); }, + sendLastate: function(target) { + if ( + (this.game.moves.length > 0 && this.vr.turn != this.game.mycolor) || + this.game.score != "*" || + this.drawOffer == "sent" || + this.rematchOffer == "sent" + ) { + // Send our "last state" informations to opponent + const L = this.game.moves.length; + const myIdx = ["w", "b"].indexOf(this.game.mycolor); + const myLastate = { + lastMove: L > 0 ? this.game.moves[L - 1] : undefined, + clock: this.game.clocks[myIdx], + // Since we played a move (or abort or resign), + // only drawOffer=="sent" is possible + drawSent: this.drawOffer == "sent", + rematchSent: this.rematchOffer == "sent", + score: this.game.score, + score: this.game.scoreMsg, + movesCount: L, + initime: this.game.initime[1 - myIdx] //relevant only if I played + }; + this.send("lastate", { data: myLastate, target: target }); + } else { + this.send("lastate", { data: {nothing: true}, target: target }); + } + }, // lastate was received, but maybe game wasn't ready yet: processLastate: function() { const data = this.lastate; @@ -811,6 +827,32 @@ export default { } else this.updateCorrGame({ drawOffer: this.game.mycolor }); } }, + addAndGotoLiveGame: function(gameInfo, callback) { + const game = Object.assign( + {}, + gameInfo, + { + // (other) Game infos: constant + fenStart: gameInfo.fen, + vname: this.game.vname, + created: Date.now(), + // Game state (including FEN): will be updated + moves: [], + clocks: [-1, -1], //-1 = unstarted + initime: [0, 0], //initialized later + score: "*" + } + ); + GameStorage.add(game, (err) => { + // No error expected. + if (!err) { + if (this.st.settings.sound) + new Audio("/sounds/newgame.flac").play().catch(() => {}); + callback(); + this.$router.push("/game/" + gameInfo.id); + } + }); + }, clickRematch: function() { if (!this.game.mycolor) return; //I'm just spectator if (this.rematchOffer == "received") { @@ -822,33 +864,12 @@ export default { vid: this.game.vid, cadence: this.game.cadence }; - let oppsid = this.getOppsid(); //may be null - this.send("rnewgame", { data: gameInfo, oppsid: oppsid }); - if (this.game.type == "live") { - const game = Object.assign( - {}, - gameInfo, - { - // (other) Game infos: constant - fenStart: gameInfo.fen, - vname: this.game.vname, - created: Date.now(), - // Game state (including FEN): will be updated - moves: [], - clocks: [-1, -1], //-1 = unstarted - initime: [0, 0], //initialized later - score: "*" - } - ); - GameStorage.add(game, (err) => { - // No error expected. - if (!err) { - if (this.st.settings.sound) - new Audio("/sounds/newgame.flac").play().catch(() => {}); - this.$router.push("/game/" + gameInfo.id); - } - }); - } + const notifyNewGame = () => { + let oppsid = this.getOppsid(); //may be null + this.send("rnewgame", { data: gameInfo, oppsid: oppsid }); + }; + if (this.game.type == "live") + this.addAndGotoLiveGame(gameInfo, notifyNewGame); else { // corr game ajax( @@ -859,6 +880,7 @@ export default { data: { gameInfo: gameInfo }, success: (response) => { gameInfo.id = response.gameId; + notifyNewGame(); this.$router.push("/game/" + response.gameId); } } @@ -903,11 +925,11 @@ export default { // - from server (one correspondance game I play[ed] or not) // - from remote peer (one live game I don't play, finished or not) loadGame: function(game, callback) { - const afterRetrieval = async game => { + const afterRetrieval = async (game) => { const vModule = await import("@/variants/" + game.vname + ".js"); window.V = vModule.VariantRules; this.vr = new V(game.fen); - const gtype = game.cadence.indexOf("d") >= 0 ? "corr" : "live"; + const gtype = this.getGameType(game); const tc = extractTime(game.cadence); const myIdx = game.players.findIndex(p => { return p.sid == this.st.user.sid || p.uid == this.st.user.id; @@ -1050,6 +1072,10 @@ export default { // Did lastate arrive before game was rendered? if (this.lastate) this.processLastate(); }); + if (this.lastateAsked) { + this.lastateAsked = false; + this.sendLastate(game.oppsid); + } if (this.gameIsLoading) { this.gameIsLoading = false; if (this.gotMoveIdx >= game.moves.length) diff --git a/client/src/views/Hall.vue b/client/src/views/Hall.vue index 4cb46ec9..ac2e26ec 100644 --- a/client/src/views/Hall.vue +++ b/client/src/views/Hall.vue @@ -685,7 +685,7 @@ export default { const game = data.data; // Ignore games where I play (will go in MyGames page) if (game.players.every(p => - p.sid != this.st.user.sid || p.id != this.st.user.id)) + p.sid != this.st.user.sid || p.uid != this.st.user.id)) { let locGame = this.games.find(g => g.id == game.id); if (!locGame) { @@ -948,6 +948,16 @@ export default { }, // NOTE: when launching game, the challenge is already being deleted launchGame: function(c) { + let players = + !!c.mycolor + ? (c.mycolor == "w" ? [c.seat, c.from] : [c.from, c.seat]) + : shuffle([c.from, c.seat]); + // Convention for players IDs in stored games is 'uid' + players.forEach(p => { + let pWithUid = p; + pWithUid["uid"] = p.id; + delete pWithUid["id"]; + }); // These game informations will be shared let gameInfo = { id: getRandString(), diff --git a/server/models/Game.js b/server/models/Game.js index e45c1827..caa15c39 100644 --- a/server/models/Game.js +++ b/server/models/Game.js @@ -39,7 +39,7 @@ const GameModel = g.cadence.match(/^[0-9dhms +]+$/) && g.fen.match(/^[a-zA-Z0-9, /-]*$/) && g.players.length == 2 && - g.players.every(p => p.id.toString().match(/^[0-9]+$/)) + g.players.every(p => p.uid.toString().match(/^[0-9]+$/)) ); }, @@ -60,7 +60,7 @@ const GameModel = const color = (idx==0 ? "w" : "b"); query = "INSERT INTO Players VALUES " + - "(" + this.lastID + "," + p.id + ",'" + color + "')"; + "(" + this.lastID + "," + p.uid + ",'" + color + "')"; db.run(query); }); cb(null, {gid: this.lastID}); @@ -99,7 +99,8 @@ const GameModel = "FROM Chats " + "WHERE gid = " + id; db.all(query, (err4, chats) => { - const game = Object.assign({}, + const game = Object.assign( + {}, gameInfo, { players: players, @@ -140,7 +141,8 @@ const GameModel = "FROM Moves " + "WHERE gid = " + id; db.get(query, (err,ret) => { - const game = Object.assign({}, + const game = Object.assign( + {}, gameInfo, { players: players, diff --git a/server/routes/games.js b/server/routes/games.js index 21aee475..a86a76dd 100644 --- a/server/routes/games.js +++ b/server/routes/games.js @@ -12,7 +12,7 @@ router.post("/games", access.logged, access.ajax, (req,res) => { const cid = req.body.cid; if ( Array.isArray(gameInfo.players) && - gameInfo.players.some(p => p.id == req.userId) && + gameInfo.players.some(p => p.uid == req.userId) && (!cid || cid.toString().match(/^[0-9]+$/)) && GameModel.checkGameInfo(gameInfo) ) { diff --git a/server/sockets.js b/server/sockets.js index 7395af15..d1489f71 100644 --- a/server/sockets.js +++ b/server/sockets.js @@ -205,7 +205,7 @@ module.exports = function(wss) { case "rnewgame": // A rematch game started: players are already informed - notifyAllBut(page, "newgame", {data: obj.data}, [sid, obj.oppsid]); + notifyAllBut(page, "newgame", {data: obj.data}, [sid]); notifyAllBut("/", "newgame", {data: obj.data}, [sid, obj.oppsid]); notifyRoom("/mygames", "newgame", {data: obj.data}); break; -- 2.44.0