First draft of game balancing solution after reconnect
authorBenjamin Auder <benjamin.auder@somewhere>
Sun, 18 Nov 2018 23:43:17 +0000 (00:43 +0100)
committerBenjamin Auder <benjamin.auder@somewhere>
Sun, 18 Nov 2018 23:43:17 +0000 (00:43 +0100)
public/javascripts/components/game.js
sockets.js

index 160c692..4a07741 100644 (file)
@@ -1,4 +1,4 @@
-// TODO: use indexedDB instead of localStorage? (more flexible...)
+// TODO: use indexedDB instead of localStorage? (more flexible: allow several games)
 
 Vue.component('my-game', {
        data: function() {
@@ -365,14 +365,13 @@ Vue.component('my-game', {
                const socketOpenListener = () => {
                        if (continuation)
                        {
-                               // TODO: check FEN integrity with opponent
                                const fen = localStorage.getItem("fen");
                                const mycolor = localStorage.getItem("mycolor");
                                const oppid = localStorage.getItem("oppid");
                                const moves = JSON.parse(localStorage.getItem("moves"));
                                this.newGame("human", fen, mycolor, oppid, moves, true);
-                               // Send ping to server, which answers pong if opponent is connected
-                               this.conn.send(JSON.stringify({code:"ping", oppid:this.oppId}));
+                               // Send ping to server (answer pong if opponent is connected)
+                               this.conn.send(JSON.stringify({code:"ping",oppid:this.oppId}));
                        }
                        else if (localStorage.getItem("newgame") === variant)
                        {
@@ -391,9 +390,46 @@ Vue.component('my-game', {
                                case "newmove": //..he played!
                                        this.play(data.move, "animate");
                                        break;
-                               case "pong": //sent when opponent stayed online after we disconnected
+                               case "pong": //received if opponent sent a ping
                                        this.oppConnected = true;
+                                       const L = this.vr.moves.length;
+                                       // Send our "last state" informations to opponent (we are still playing)
+                                       this.conn.send(JSON.stringify({
+                                               code:"lastate",
+                                               oppid:this.oppId,
+                                               lastMove:L>0?this.vr.moves[L-1]:undefined,
+                                               movesCount:L,
+                                       }));
                                        break;
+                               case "lastate": //got opponent infos about last move (we might have resigned)
+                                       if (this.mode!="human" || this.oppid!=data.oppid)
+                                       {
+                                               // OK, we resigned
+                                               this.conn.send(JSON.stringify({
+                                                       code:"lastate",
+                                                       oppid:this.oppId,
+                                                       lastMove:undefined,
+                                                       movesCount:-1,
+                                               }));
+                                       }
+                                       else if (data.movesCount < 0)
+                                       {
+                                               // OK, he resigned
+                                               this.endGame(this.mycolor=="w"?"1-0":"0-1");
+                                       }
+                                       else if (data.movesCount < this.vr.moves.length)
+                                       {
+                                               // We must tell last move to opponent
+                                               const L = this.vr.moves.length;
+                                               this.conn.send(JSON.stringify({
+                                                       code:"lastate",
+                                                       oppid:this.oppId,
+                                                       lastMove:this.vr.moves[L-1],
+                                                       movesCount:L,
+                                               }));
+                                       }
+                                       else if (data.movesCount > this.vr.moves.length) //just got last move from him
+                                               this.play(data.lastMove, "animate");
                                case "resign": //..you won!
                                        this.endGame(this.mycolor=="w"?"1-0":"0-1");
                                        break;
@@ -433,7 +469,7 @@ Vue.component('my-game', {
                                try {
                                        this.conn.send(JSON.stringify({code: "resign", oppid: this.oppid}));
                                } catch (INVALID_STATE_ERR) {
-                                       return; //resign failed for some reason...
+                                       return; //socket is not ready (and not yet reconnected)
                                }
                        }
                        this.endGame(this.mycolor=="w"?"0-1":"1-0");
@@ -646,15 +682,7 @@ Vue.component('my-game', {
                        this.incheck = this.vr.getCheckSquares(move, oppCol); //is opponent in check?
                        // Not programmatic, or animation is over
                        if (this.mode == "human" && this.vr.turn == this.mycolor)
-                       {
-                               if (!this.oppConnected)
-                                       return; //abort move if opponent is gone
-                               try {
-                                       this.conn.send(JSON.stringify({code:"newmove", move:move, oppid:this.oppid}));
-                               } catch(INVALID_STATE_ERR) {
-                                       return; //abort also if sending failed
-                               }
-                       }
+                               this.conn.send(JSON.stringify({code:"newmove", move:move, oppid:this.oppid}));
                        new Audio("/sounds/chessmove1.mp3").play();
                        this.vr.play(move, "ingame");
                        if (this.mode == "human")
index f3d479d..8548e2f 100644 (file)
@@ -1,16 +1,6 @@
-//const url = require('url');
+const url = require('url');
 const Variants = require("./variants");
 
-function getJsonFromUrl(url) {
-       var query = url.substr(2); //starts with "/?"
-       var result = {};
-       query.split("&").forEach(function(part) {
-               var item = part.split("=");
-               result[item[0]] = decodeURIComponent(item[1]);
-       });
-       return result;
-}
-
 module.exports = function(wss) {
 
        let clients = { "index": {} };
@@ -18,21 +8,10 @@ module.exports = function(wss) {
        for (const v of Variants)
                clients[v.name] = {};
 
-       // (resign, newgame, newmove). See https://github.com/websockets/ws/blob/master/lib/websocket.js around line 313
-       // TODO: awaiting newmove, resign, (+newgame?) :: in memory structure (use Redis ?)
-       let newmoves = {};
-       let newresign = {};
-       for (const v of Variants)
-       {
-               newmoves[v.name] = {};
-               newresign[v.name] = {};
-       }
-
        wss.on("connection", (socket, req) => {
-               //const params = new URL("http://localhost" + req.url).searchParams;
-               var query = getJsonFromUrl(req.url);
-               const sid = query["sid"]; //params.get("sid");
-               const page = query["page"]; //params.get("page");
+               const params = new URL("http://localhost" + req.url).searchParams;
+               const sid = params.get("sid");
+               const page = params.get("page");
                clients[page][sid] = socket;
                if (page == "index")
                {
@@ -52,30 +31,22 @@ module.exports = function(wss) {
                        Object.keys(clients[page]).forEach( k => {
                                clients[page][k].send(JSON.stringify({code:"connect",id:sid}));
                        });
-                       if (!!newmoves[page][sid])
-                       {
-                               socket.send(JSON.stringify({code:"newmove",move:newmoves[page][sid]}));
-                               delete newmoves[page][sid];
-                       }
-                       if (!!newresign[page][sid])
-                       {
-                               socket.send(JSON.stringify({code:"resign"}));
-                               delete newresign[page][sid];
-                       }
                        socket.on("message", objtxt => {
                                let obj = JSON.parse(objtxt);
                                switch (obj.code)
                                {
                                        case "newmove":
-                                               if (!!clients[page][obj.oppid]) // && clients[page][obj.oppid].readyState == WebSocket.OPEN)
+                                               if (!!clients[page][obj.oppid])
                                                        clients[page][obj.oppid].send(JSON.stringify({code:"newmove",move:obj.move}));
-                                               else
-                                                       newmoves[page][obj.oppid] = obj.move;
                                                break;
                                        case "ping":
-                                               if (!!clients[page][obj.oppid]) // && clients[page][obj.oppid].readyState == WebSocket.OPEN)
+                                               if (!!clients[page][obj.oppid])
                                                        socket.send(JSON.stringify({code:"pong"}));
                                                break;
+                                       case "lastate":
+                                               if (!!clients[page][obj.oppid])
+                                                       clients[page][obj.oppid].send(objtxt);
+                                               break;
                                        case "newgame":
                                                if (!!games[page])
                                                {
@@ -85,16 +56,15 @@ module.exports = function(wss) {
                                                        delete games[page];
                                                        const mycolor = Math.random() < 0.5 ? 'w' : 'b';
                                                        socket.send(JSON.stringify({code:"newgame",fen:fen,oppid:oppId,color:mycolor}));
-                                                       clients[page][oppId].send(JSON.stringify({code:"newgame",fen:fen,oppid:sid,color:mycolor=="w"?"b":"w"}));
+                                                       if (!!clients[page][oppId])
+                                                               clients[page][oppId].send(JSON.stringify({code:"newgame",fen:fen,oppid:sid,color:mycolor=="w"?"b":"w"}));
                                                }
                                                else
                                                        games[page] = {id:sid, fen:obj.fen}; //wait for opponent
                                                break;
                                        case "resign":
-                                               if (!!clients[page][obj.oppid]) // && clients[page][obj.oppid].readyState == WebSocket.OPEN)
+                                               if (!!clients[page][obj.oppid])
                                                        clients[page][obj.oppid].send(JSON.stringify({code:"resign"}));
-                                               else
-                                                       newresign[page][obj.oppid] = true;
                                                break;
                                }
                        });