break;
// Receive opponent's move:
case "newmove":
+ send("gotmove", {fen: obj.fen, gid: gid});
+ if (obj.fen == lastFen) break; //got this move already
+ lastFen = obj.fen;
if (document.hidden) notifyMe("move");
vr.playReceivedMove(obj.moves, () => {
if (vr.getCurrentScore(obj.moves[obj.moves.length-1]) != "*") {
else toggleTurnIndicator(true);
});
break;
+ // The server notifies that it got our move:
+ case "gotmove":
+ if (obj.fen == lastFen) {
+ curMoves = [];
+ clearTimeout(timeout1);
+ clearTimeout(timeout2);
+ clearTimeout(timeout3);
+ callbackAfterConfirmation();
+ }
+ break;
// Opponent stopped game (draw, abort, resign...)
case "gameover":
toggleVisible("gameStopped");
}
}
-let curMoves = [];
-const afterPlay = (move) => { //pack into one moves array, then send
+let curMoves = [],
+ lastFen, lastMove,
+ timeout1, timeout2, timeout3;
+const callbackAfterConfirmation = () => {
+ const result = vr.getCurrentScore(lastMove);
+ if (result != "*") {
+ setTimeout( () => {
+ toggleVisible("gameStopped");
+ send("gameover", { gid: gid });
+ }, 2000);
+ }
+};
+const afterPlay = (move) => {
+ // Pack into one moves array, then send
curMoves.push({
appear: move.appear,
vanish: move.vanish,
start: move.start,
end: move.end
});
+ lastMove = move;
if (vr.turn != playerColor) {
toggleTurnIndicator(false);
- send("newmove", { gid: gid, moves: curMoves, fen: vr.getFen() });
- curMoves = [];
- const result = vr.getCurrentScore(move);
- if (result != "*") {
- setTimeout( () => {
- toggleVisible("gameStopped");
- send("gameover", { gid: gid });
- }, 2000);
- }
+ lastFen = vr.getFen();
+ const sendMove =
+ () => send("newmove", {gid: gid, moves: curMoves, fen: lastFen});
+ // Send move until we obtain confirmation or timeout, then callback
+ sendMove();
+ timeout1 = setTimeout(sendMove, 500);
+ timeout2 = setTimeout(sendMove, 1500);
+ timeout3 = setTimeout(
+ () => alert("The move may be lost :( Please reload"),
+ 3000);
}
};
let challenges = {}; //variantName --> socketId, name
let games = {}; //gameId --> gameInfo (vname, fen, players, options)
let sockets = {}; //socketId --> socket
+let sendmoveTimeout1 = {},
+ sendmoveTimeout2 = {},
+ sendmoveRetry = {},
+ stopRetry = {};
const variants = require("./variants.js");
+const clearTrySendMove = (gid) => {
+ clearTimeout(sendmoveTimeout1[gid]);
+ clearTimeout(sendmoveTimeout2[gid]);
+ clearInterval(sendmoveRetry[gid]);
+ clearTimeout(stopRetry[gid]);
+};
+
const send = (sid, code, data) => {
const socket = sockets[sid];
// If a player delete local infos and then try to resume a game,
delete challenges[obj.vname];
break;
// Receive rematch
- case "rematch": {
+ case "rematch":
if (!games[obj.gid]) send(sid, "closerematch");
else {
const myIndex = (games[obj.gid].players[0].sid == sid ? 0 : 1);
}
}
break;
- }
- // Rematch cancellation
- case "norematch": {
+ // Rematch cancellation
+ case "norematch":
if (games[obj.gid]) {
const myIndex = (games[obj.gid].players[0].sid == sid ? 0 : 1);
send(games[obj.gid].players[1-myIndex].sid, "closerematch");
}
break;
- }
// Create game vs. friend
- case "creategame":
+ case "creategame": {
let players = [
{ sid: obj.player.sid, name: obj.player.name },
undefined
}
launchGame(obj.vname, players, obj.options);
break;
+ }
// Join game vs. friend
- case "joingame": {
+ case "joingame":
if (!games[obj.gid]) send(sid, "jointoolate");
else {
// Join a game (started by some other player)
send(games[obj.gid].players[i].sid, "gamestart", gameInfo);
}
break;
- }
// Relay a move + update games object
- case "newmove": {
- // TODO?: "pingback" strategy to ensure that move was transmitted
+ case "newmove":
+ // If already received this move: skip
+ if (games[obj.gid].fen == obj.fen) break;
+ // Notify sender that the move is received:
+ send(sid, "gotmove", {fen: obj.fen});
games[obj.gid].fen = obj.fen;
const playingWhite = (games[obj.gid].players[0].sid == sid);
const oppSid = games[obj.gid].players[playingWhite ? 1 : 0].sid;
- send(oppSid, "newmove", { moves: obj.moves });
+ const sendMove =
+ // NOTE: sending FEN also, to check it in "gotmove" below
+ () => send(oppSid, "newmove", {moves: obj.moves, fen: obj.fen});
+ sendMove();
+ sendmoveTimeout1[obj.gid] = setTimeout(sendMove, 500);
+ sendmoveTimeout2[obj.gid] = setTimeout(sendMove, 1500);
+ sendmoveRetry[obj.gid] = setInterval(sendMove, 5000);
+ stopRetry[obj.gid] = setTimeout(clearTrySendMove, 31000);
+ break;
+ case "gotmove":
+ if (games[obj.gid].fen == obj.fen) clearTrySendMove(obj.gid);
break;
- }
// Relay "game ends" message
case "gameover": {
const playingWhite = (games[obj.gid].players[0].sid == sid);