Fix stuff implementing the re-synchronization after connection loss

This commit is contained in:
Tissevert 2020-01-25 10:56:55 +01:00
parent 19aa959c64
commit 81216e3f01
8 changed files with 119 additions and 89 deletions

View File

@ -11,7 +11,7 @@ function HandCard(name) {
return card; return card;
function onClick() { function onClick() {
if(State.state.playing && State.state.step == "ToPlay") { if(State.globalState.playing && State.globalState.step == "ToPlay") {
if(State.getSelected() != undefined) { if(State.getSelected() != undefined) {
State.select(false); State.select(false);
} else { } else {

View File

@ -17,7 +17,7 @@ function RiverCard(name) {
var withCard = State.getSelected().value.name; var withCard = State.getSelected().value.name;
State.select(false); State.select(false);
State.play( State.play(
State.state.step == 'ToPlay' ? State.globalState.step == 'ToPlay' ?
{capture: [withCard, name]} : {choose: name} {capture: [withCard, name]} : {choose: name}
); );
} }

View File

@ -5,7 +5,7 @@ import * as TurnedCard from GUI.Card.TurnedCard;
import * as Screen from GUI.Screen; import * as Screen from GUI.Screen;
import {animate, catchUp, delay, getQueue} from GUI.Screen.Game.Animation; import {animate, catchUp, delay, getQueue} from GUI.Screen.Game.Animation;
import { import {
dom, init as initState, play, select, sets, state dom, init as initState, play, select, sets, globalState
} from GUI.Screen.Game.State; } from GUI.Screen.Game.State;
import Hanafuda; import Hanafuda;
import I18n; import I18n;
@ -52,7 +52,7 @@ function fail(errorCode) {
} }
function getSavedStates(gameID) { 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'); return states != undefined ? Async.wrap(states) : fail('gameNotFound');
} }
@ -117,13 +117,13 @@ function setGame(state) {
function handleStep(state) { function handleStep(state) {
return function(f) { return function(f) {
handleTurnedCard(state, f); handleTurnedCard(state, f);
if(state.step == "Scored") { if(globalState.step == "Scored") {
if(state.playing) { if(globalState.playing) {
askKoikoi(state, f); askKoikoi(state, f);
} else { } else {
theyScored(state, f); theyScored(state, f);
} }
} else if (state.step == "Over") { } else if (globalState.step == "Over") {
gameEnd(state, f); gameEnd(state, f);
} else { } else {
f(); f();
@ -132,11 +132,11 @@ function handleStep(state) {
} }
function handleTurnedCard(state, f) { function handleTurnedCard(state, f) {
if(state.step == "Turned") { if(globalState.step == "Turned") {
setTurned(state.public.step.contents); setTurned(state.public.step.contents);
} else { } else {
if(state.step == "ToPlay" && state.public.playing == state.public.oyake) { if(globalState.step == "ToPlay" && state.public.playing == state.public.oyake) {
rest.className = ["card", "turn" + state.public.coordinates.turn].join(' '); dom.rest.className = ["card", "turn" + state.public.coordinates.turn].join(' ');
} }
if(deck.lastChild.id != "rest") { if(deck.lastChild.id != "rest") {
deck.removeChild(deck.lastChild); deck.removeChild(deck.lastChild);
@ -188,18 +188,18 @@ function applyDiff(state) {
function setStatus(game) { function setStatus(game) {
Dom.clear(dom.status); Dom.clear(dom.status);
state.game = game; globalState.game = game;
state.step = game.public.step.tag; globalState.step = game.public.step.tag;
if(game.public.coordinates.month != state.month) { if(game.public.coordinates.month != globalState.month) {
state.month = game.public.coordinates.month; globalState.month = game.public.coordinates.month;
} }
dom.status.appendChild( 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; var turn = null;
state.playing = Session.is(game.public.playing); globalState.playing = Session.is(game.public.playing);
if(state.playing) { if(globalState.playing) {
sets.you.hand.dom.classList.toggle("yourTurn", state.step == "ToPlay"); sets.you.hand.dom.classList.toggle("yourTurn", globalState.step == "ToPlay");
turn = I18n.get("yourTurn"); turn = I18n.get("yourTurn");
} else { } else {
sets.you.hand.dom.classList.remove("yourTurn"); sets.you.hand.dom.classList.remove("yourTurn");
@ -246,8 +246,8 @@ function setTheirCards(game) {
} }
function setTurned(cardName) { function setTurned(cardName) {
state.turnedCard = TurnedCard.make(cardName); globalState.turnedCard = TurnedCard.make(cardName);
if(state.playing) { if(globalState.playing) {
select(state.turnedCard); select(globalState.turnedCard);
} }
} }

View File

@ -59,8 +59,8 @@ function handleSource(movement, movingCards, side, cardLeft) {
} else { } else {
var cardSet = {}; var cardSet = {};
var name = cardLeft.card.value.name; var name = cardLeft.card.value.name;
cardSet[name] = State.state.turnedCard || TurnedCard.make(name); cardSet[name] = State.globalState.turnedCard || TurnedCard.make(name);
State.state.turnedCard = null; State.globalState.turnedCard = null;
movingCards.push( movingCards.push(
moveCard({card: cardSet, dom: State.dom.deck}, cardLeft.dest, cardLeft.card) moveCard({card: cardSet, dom: State.dom.deck}, cardLeft.dest, cardLeft.card)
); );
@ -70,7 +70,7 @@ function handleSource(movement, movingCards, side, cardLeft) {
function cardMoves(movement) { function cardMoves(movement) {
var card; var card;
var movingCards = []; var movingCards = [];
var side = (State.state.playing) ? 'you' : 'them'; var side = (State.globalState.playing) ? 'you' : 'them';
var cardLeft = handleCaptures(movement, movingCards, side); var cardLeft = handleCaptures(movement, movingCards, side);
handleSource(movement, movingCards, side, cardLeft); handleSource(movement, movingCards, side, cardLeft);
return movingCards; return movingCards;

View File

@ -9,7 +9,7 @@ var dom = {
}; };
var selected; var selected;
var sets = {}; var sets = {};
var state = { var globalState = {
game: null, game: null,
playing: false, playing: false,
step: null, step: null,
@ -25,7 +25,7 @@ return {
play: play, play: play,
select: select, select: select,
sets: sets, sets: sets,
state: state globalState: globalState
}; };
function init() { function init() {
@ -64,7 +64,7 @@ function play(move) {
Messaging.send({ Messaging.send({
tag: "Play", tag: "Play",
move: move, move: move,
onGame: state.game onGame: globalState.game
}); });
} }

View File

@ -5,8 +5,10 @@ import Session;
import Table; import Table;
import Time; import Time;
var states = Table.make(function(o) {return 0;});
states.load('games.state');
var metadata = Table.make(function(o) {return o.value.date;}); var metadata = Table.make(function(o) {return o.value.date;});
metadata.insertAll(Save.get('games.metadata') || {}); metadata.load('games.metadata');
initMessageHandlers(); initMessageHandlers();
return { return {
@ -14,29 +16,47 @@ return {
proposal: proposal proposal: proposal
}; };
function makeMetadata(state) { function initMessageHandlers() {
var sessionKey = Session.getKey(); Messaging.addEventListener(["Game"], function(o) {
return Time.timestamp({ var gameID = o.state.public.coordinates.gameID;
vs: player(state.public.nextPlayer[sessionKey]), pushState(gameID, o.state);
yourTurn: state.public.playing == sessionKey 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) { function isAgainst(state, playerID) {
metadata.insert( return state.latest.public.nextPlayer[Session.getKey()] == playerID;
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 compare(gameCoordinatesA, gameCoordinatesB) { function compare(gameCoordinatesA, gameCoordinatesB) {
@ -53,29 +73,27 @@ function compare(gameCoordinatesA, gameCoordinatesB) {
} }
} }
function initMessageHandlers() { function getMetadata(state) {
Messaging.addEventListener(["Game"], function(o) { var sessionKey = Session.getKey();
var gameID = o.state.public.coordinates.gameID; return Time.timestamp({
var metadata = makeMetadata(o.state); vs: player(state.public.nextPlayer[sessionKey]),
pushState(gameID, o.state); yourTurn: state.public.playing == sessionKey
Save.set("games.metadata." + gameID, metadata);
metadata.insert(gameID, metadata);
}); });
}
Messaging.addEventListener(["Relay", "Sync"], function(o) {
var gameID = o.message.latestKnown.gameID; function proposal(playerID, yourTurn) {
var latestKnownHere = Save.get("games.state." + gameID + ".latest"); metadata.insert(
switch(compare(latestKnownHere, o.message.latestKnown)) { playerID,
case -1: Messaging.send({tag: "Yield", onGameID: gameID}); Time.timestamp({vs: player(playerID), yourTurn: yourTurn})
case 1: Messaging.send({tag: "Sync", latestKnown: latestKnownHere}); );
} }
});
function pushState(gameID, newState) {
Messaging.addEventListener(["Relay", "Yield"], function(o) { if(states.get(gameID) == undefined) {
var gameID = o.message.latestKnown.gameID; states.insert(gameID, {});
var latestKnownHere = Save.get("games.message." + gameID + ".latest"); }
if(o.from == latestKnownHere.public.nextPlayer[Session.getKey()]) { var state = states.get(gameID);
Messaging.send({tag: "Share", gameSave: latestKnownHere}); state.former = state.latest;
} state.latest = newState;
}); states.save('games.state');
} }

View File

@ -14,19 +14,21 @@ function player(key) {
return {id: key, name: players.get(key)}; return {id: key, name: players.get(key)};
} }
function initMessageHandlers() { function enterAll(o) {
Messaging.addEventListener(["Okaeri"], function(o) { for(key in o) {
players.insertAll(o.room); enterPlayer(key, o[key]);
}); }
Messaging.addEventListener(["Welcome"], function(o) { }
players.insertAll(o.room);
}); function enterPlayer(key, name) {
Messaging.addEventListener(["LogIn"], function(o) { if(!Session.is(key)) {
if(!Session.is(o.from)) { players.insert(key, name);
players.insert(o.from, o.as); }
} }
});
Messaging.addEventListener(["LogOut"], function(o) { function initMessageHandlers() {
players.remove(o.from); 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);});
} }

View File

@ -1,3 +1,4 @@
import Save;
import of from UnitJS.Fun; import of from UnitJS.Fun;
import {compare, of, proj} from UnitJS.Fun; import {compare, of, proj} from UnitJS.Fun;
@ -8,7 +9,9 @@ function Table(sortCriterion) {
getAll: getAll, getAll: getAll,
insert: insert, insert: insert,
insertAll: insertAll, insertAll: insertAll,
remove: remove load: load,
remove: remove,
save
}; };
function get(key) { function get(key) {
@ -22,7 +25,6 @@ function Table(sortCriterion) {
.sort(compare(sortCriterion)); .sort(compare(sortCriterion));
} }
function insert(key, value) { function insert(key, value) {
items[key] = value; items[key] = value;
} }
@ -33,9 +35,17 @@ function Table(sortCriterion) {
} }
} }
function load(path) {
insertAll(Save.get(path) || {});
}
function remove(key) { function remove(key) {
delete items[key]; delete items[key];
} }
function save(path) {
Save.set(path, items);
}
} }
return { return {