From 81216e3f01666c14ff8bf83b946d89d71408d4cf Mon Sep 17 00:00:00 2001 From: Tissevert Date: Sat, 25 Jan 2020 10:56:55 +0100 Subject: [PATCH] Fix stuff implementing the re-synchronization after connection loss --- js/GUI/Card/HandCard.js | 2 +- js/GUI/Card/RiverCard.js | 2 +- js/GUI/Screen/Game.js | 38 +++++------ js/GUI/Screen/Game/Animation.js | 6 +- js/GUI/Screen/Game/State.js | 6 +- js/Games.js | 108 +++++++++++++++++++------------- js/Room.js | 32 +++++----- js/Table.js | 14 ++++- 8 files changed, 119 insertions(+), 89 deletions(-) diff --git a/js/GUI/Card/HandCard.js b/js/GUI/Card/HandCard.js index baabc67..1a007e4 100644 --- a/js/GUI/Card/HandCard.js +++ b/js/GUI/Card/HandCard.js @@ -11,7 +11,7 @@ function HandCard(name) { return card; function onClick() { - if(State.state.playing && State.state.step == "ToPlay") { + if(State.globalState.playing && State.globalState.step == "ToPlay") { if(State.getSelected() != undefined) { State.select(false); } else { diff --git a/js/GUI/Card/RiverCard.js b/js/GUI/Card/RiverCard.js index 9983919..c3ef965 100644 --- a/js/GUI/Card/RiverCard.js +++ b/js/GUI/Card/RiverCard.js @@ -17,7 +17,7 @@ function RiverCard(name) { var withCard = State.getSelected().value.name; State.select(false); State.play( - State.state.step == 'ToPlay' ? + State.globalState.step == 'ToPlay' ? {capture: [withCard, name]} : {choose: name} ); } diff --git a/js/GUI/Screen/Game.js b/js/GUI/Screen/Game.js index 9fa4866..642b185 100644 --- a/js/GUI/Screen/Game.js +++ b/js/GUI/Screen/Game.js @@ -5,7 +5,7 @@ import * as TurnedCard from GUI.Card.TurnedCard; import * as Screen from GUI.Screen; import {animate, catchUp, delay, getQueue} from GUI.Screen.Game.Animation; import { - dom, init as initState, play, select, sets, state + dom, init as initState, play, select, sets, globalState } from GUI.Screen.Game.State; import Hanafuda; import I18n; @@ -52,7 +52,7 @@ function fail(errorCode) { } function getSavedStates(gameID) { - var states = Save.get('games.message.Game#' + gameID); + var states = Save.get('games.state.Game#' + gameID); return states != undefined ? Async.wrap(states) : fail('gameNotFound'); } @@ -117,13 +117,13 @@ function setGame(state) { function handleStep(state) { return function(f) { handleTurnedCard(state, f); - if(state.step == "Scored") { - if(state.playing) { + if(globalState.step == "Scored") { + if(globalState.playing) { askKoikoi(state, f); } else { theyScored(state, f); } - } else if (state.step == "Over") { + } else if (globalState.step == "Over") { gameEnd(state, f); } else { f(); @@ -132,11 +132,11 @@ function handleStep(state) { } function handleTurnedCard(state, f) { - if(state.step == "Turned") { + if(globalState.step == "Turned") { setTurned(state.public.step.contents); } else { - if(state.step == "ToPlay" && state.public.playing == state.public.oyake) { - rest.className = ["card", "turn" + state.public.coordinates.turn].join(' '); + if(globalState.step == "ToPlay" && state.public.playing == state.public.oyake) { + dom.rest.className = ["card", "turn" + state.public.coordinates.turn].join(' '); } if(deck.lastChild.id != "rest") { deck.removeChild(deck.lastChild); @@ -188,18 +188,18 @@ function applyDiff(state) { function setStatus(game) { Dom.clear(dom.status); - state.game = game; - state.step = game.public.step.tag; - if(game.public.coordinates.month != state.month) { - state.month = game.public.coordinates.month; + globalState.game = game; + globalState.step = game.public.step.tag; + if(game.public.coordinates.month != globalState.month) { + globalState.month = game.public.coordinates.month; } dom.status.appendChild( - Dom.make('li', {textContent: I18n.get('monthFlower')(I18n.get(state.month))}) + Dom.make('li', {textContent: I18n.get('monthFlower')(I18n.get(globalState.month))}) ); var turn = null; - state.playing = Session.is(game.public.playing); - if(state.playing) { - sets.you.hand.dom.classList.toggle("yourTurn", state.step == "ToPlay"); + globalState.playing = Session.is(game.public.playing); + if(globalState.playing) { + sets.you.hand.dom.classList.toggle("yourTurn", globalState.step == "ToPlay"); turn = I18n.get("yourTurn"); } else { sets.you.hand.dom.classList.remove("yourTurn"); @@ -246,8 +246,8 @@ function setTheirCards(game) { } function setTurned(cardName) { - state.turnedCard = TurnedCard.make(cardName); - if(state.playing) { - select(state.turnedCard); + globalState.turnedCard = TurnedCard.make(cardName); + if(globalState.playing) { + select(globalState.turnedCard); } } diff --git a/js/GUI/Screen/Game/Animation.js b/js/GUI/Screen/Game/Animation.js index ffdd328..9cedb3b 100644 --- a/js/GUI/Screen/Game/Animation.js +++ b/js/GUI/Screen/Game/Animation.js @@ -59,8 +59,8 @@ function handleSource(movement, movingCards, side, cardLeft) { } else { var cardSet = {}; var name = cardLeft.card.value.name; - cardSet[name] = State.state.turnedCard || TurnedCard.make(name); - State.state.turnedCard = null; + cardSet[name] = State.globalState.turnedCard || TurnedCard.make(name); + State.globalState.turnedCard = null; movingCards.push( moveCard({card: cardSet, dom: State.dom.deck}, cardLeft.dest, cardLeft.card) ); @@ -70,7 +70,7 @@ function handleSource(movement, movingCards, side, cardLeft) { function cardMoves(movement) { var card; var movingCards = []; - var side = (State.state.playing) ? 'you' : 'them'; + var side = (State.globalState.playing) ? 'you' : 'them'; var cardLeft = handleCaptures(movement, movingCards, side); handleSource(movement, movingCards, side, cardLeft); return movingCards; diff --git a/js/GUI/Screen/Game/State.js b/js/GUI/Screen/Game/State.js index 17fe3ba..570b944 100644 --- a/js/GUI/Screen/Game/State.js +++ b/js/GUI/Screen/Game/State.js @@ -9,7 +9,7 @@ var dom = { }; var selected; var sets = {}; -var state = { +var globalState = { game: null, playing: false, step: null, @@ -25,7 +25,7 @@ return { play: play, select: select, sets: sets, - state: state + globalState: globalState }; function init() { @@ -64,7 +64,7 @@ function play(move) { Messaging.send({ tag: "Play", move: move, - onGame: state.game + onGame: globalState.game }); } diff --git a/js/Games.js b/js/Games.js index c7081b1..c5e6d9c 100644 --- a/js/Games.js +++ b/js/Games.js @@ -5,8 +5,10 @@ import Session; import Table; import Time; +var states = Table.make(function(o) {return 0;}); +states.load('games.state'); var metadata = Table.make(function(o) {return o.value.date;}); -metadata.insertAll(Save.get('games.metadata') || {}); +metadata.load('games.metadata'); initMessageHandlers(); return { @@ -14,29 +16,47 @@ return { proposal: proposal }; -function makeMetadata(state) { - var sessionKey = Session.getKey(); - return Time.timestamp({ - vs: player(state.public.nextPlayer[sessionKey]), - yourTurn: state.public.playing == sessionKey +function initMessageHandlers() { + Messaging.addEventListener(["Game"], function(o) { + var gameID = o.state.public.coordinates.gameID; + pushState(gameID, o.state); + metadata.insert(gameID, getMetadata(o.state)); + metadata.save('games.metadata'); }); + + Messaging.addEventListener(["LogIn"], function(o) { + var gamesAgainst = states.getAll( + function(game) {return isAgainst(game.value, o.from);} + ); + gamesAgainst.forEach(function(game) { + Messaging.send({ + tag: "Sync", + latestKnown: game.value.latest.public.coordinates, + to: o.from + }); + }); + }); + + Messaging.addEventListener(["Relay", "Sync"], function(o) { + var gameID = o.message.latestKnown.gameID; + var state = states.get(gameID); + switch(state != undefined && compare(state.latest, o.message.latestKnown)) { + case -1: Messaging.send({tag: "Yield", onGameID: gameID}); + case 1: Messaging.send({tag: "Share", gameSave: state.latest}); + } + }); + + Messaging.addEventListener(["Relay", "Yield"], function(o) { + var gameID = o.message.onGameID; + var state = states.get(gameID); + if(state != undefined && isAgainst(state, o.from)) { + Messaging.send({tag: "Share", gameSave: state.latest}); + } + }); } -function proposal(playerID, yourTurn) { - metadata.insert( - playerID, - Time.timestamp({vs: player(playerID), yourTurn: yourTurn}) - ); -} - -function pushState(gameID, state) { - var latestPath = "games.state." + gameID + ".latest"; - var formerPath = "games.state." + gameID + ".former"; - var former = Save.get(latestPath); - if(former != undefined) { - Save.set(formerPath, former); - } - Save.set(latestPath, state); +function isAgainst(state, playerID) { + return state.latest.public.nextPlayer[Session.getKey()] == playerID; } function compare(gameCoordinatesA, gameCoordinatesB) { @@ -53,29 +73,27 @@ function compare(gameCoordinatesA, gameCoordinatesB) { } } -function initMessageHandlers() { - Messaging.addEventListener(["Game"], function(o) { - var gameID = o.state.public.coordinates.gameID; - var metadata = makeMetadata(o.state); - pushState(gameID, o.state); - Save.set("games.metadata." + gameID, metadata); - metadata.insert(gameID, metadata); +function getMetadata(state) { + var sessionKey = Session.getKey(); + return Time.timestamp({ + vs: player(state.public.nextPlayer[sessionKey]), + yourTurn: state.public.playing == sessionKey }); - - Messaging.addEventListener(["Relay", "Sync"], function(o) { - var gameID = o.message.latestKnown.gameID; - var latestKnownHere = Save.get("games.state." + gameID + ".latest"); - switch(compare(latestKnownHere, o.message.latestKnown)) { - case -1: Messaging.send({tag: "Yield", onGameID: gameID}); - case 1: Messaging.send({tag: "Sync", latestKnown: latestKnownHere}); - } - }); - - Messaging.addEventListener(["Relay", "Yield"], function(o) { - var gameID = o.message.latestKnown.gameID; - var latestKnownHere = Save.get("games.message." + gameID + ".latest"); - if(o.from == latestKnownHere.public.nextPlayer[Session.getKey()]) { - Messaging.send({tag: "Share", gameSave: latestKnownHere}); - } - }); +} + +function proposal(playerID, yourTurn) { + metadata.insert( + playerID, + Time.timestamp({vs: player(playerID), yourTurn: yourTurn}) + ); +} + +function pushState(gameID, newState) { + if(states.get(gameID) == undefined) { + states.insert(gameID, {}); + } + var state = states.get(gameID); + state.former = state.latest; + state.latest = newState; + states.save('games.state'); } diff --git a/js/Room.js b/js/Room.js index 72cf0f7..3eafffb 100644 --- a/js/Room.js +++ b/js/Room.js @@ -14,19 +14,21 @@ function player(key) { return {id: key, name: players.get(key)}; } -function initMessageHandlers() { - Messaging.addEventListener(["Okaeri"], function(o) { - players.insertAll(o.room); - }); - Messaging.addEventListener(["Welcome"], function(o) { - players.insertAll(o.room); - }); - Messaging.addEventListener(["LogIn"], function(o) { - if(!Session.is(o.from)) { - players.insert(o.from, o.as); - } - }); - Messaging.addEventListener(["LogOut"], function(o) { - players.remove(o.from); - }); +function enterAll(o) { + for(key in o) { + enterPlayer(key, o[key]); + } +} + +function enterPlayer(key, name) { + if(!Session.is(key)) { + players.insert(key, name); + } +} + +function initMessageHandlers() { + Messaging.addEventListener(["Okaeri"], function(o) {enterAll(o.room);}); + Messaging.addEventListener(["Welcome"], function(o) {enterAll(o.room);}); + Messaging.addEventListener(["LogIn"], function(o) {enterPlayer(o.from, o.as);}); + Messaging.addEventListener(["LogOut"], function(o) {players.remove(o.from);}); } diff --git a/js/Table.js b/js/Table.js index 334f92f..66e82bc 100644 --- a/js/Table.js +++ b/js/Table.js @@ -1,3 +1,4 @@ +import Save; import of from UnitJS.Fun; import {compare, of, proj} from UnitJS.Fun; @@ -8,7 +9,9 @@ function Table(sortCriterion) { getAll: getAll, insert: insert, insertAll: insertAll, - remove: remove + load: load, + remove: remove, + save }; function get(key) { @@ -22,7 +25,6 @@ function Table(sortCriterion) { .sort(compare(sortCriterion)); } - function insert(key, value) { items[key] = value; } @@ -33,9 +35,17 @@ function Table(sortCriterion) { } } + function load(path) { + insertAll(Save.get(path) || {}); + } + function remove(key) { delete items[key]; } + + function save(path) { + Save.set(path, items); + } } return {