Fix stuff implementing the re-synchronization after connection loss
This commit is contained in:
parent
19aa959c64
commit
81216e3f01
8 changed files with 119 additions and 89 deletions
|
@ -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 {
|
||||||
|
|
|
@ -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}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
100
js/Games.js
100
js/Games.js
|
@ -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) {
|
function proposal(playerID, yourTurn) {
|
||||||
var gameID = o.message.latestKnown.gameID;
|
metadata.insert(
|
||||||
var latestKnownHere = Save.get("games.state." + gameID + ".latest");
|
playerID,
|
||||||
switch(compare(latestKnownHere, o.message.latestKnown)) {
|
Time.timestamp({vs: player(playerID), yourTurn: yourTurn})
|
||||||
case -1: Messaging.send({tag: "Yield", onGameID: gameID});
|
);
|
||||||
case 1: Messaging.send({tag: "Sync", latestKnown: latestKnownHere});
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
Messaging.addEventListener(["Relay", "Yield"], function(o) {
|
function pushState(gameID, newState) {
|
||||||
var gameID = o.message.latestKnown.gameID;
|
if(states.get(gameID) == undefined) {
|
||||||
var latestKnownHere = Save.get("games.message." + gameID + ".latest");
|
states.insert(gameID, {});
|
||||||
if(o.from == latestKnownHere.public.nextPlayer[Session.getKey()]) {
|
|
||||||
Messaging.send({tag: "Share", gameSave: latestKnownHere});
|
|
||||||
}
|
}
|
||||||
});
|
var state = states.get(gameID);
|
||||||
|
state.former = state.latest;
|
||||||
|
state.latest = newState;
|
||||||
|
states.save('games.state');
|
||||||
}
|
}
|
||||||
|
|
30
js/Room.js
30
js/Room.js
|
@ -14,19 +14,21 @@ function player(key) {
|
||||||
return {id: key, name: players.get(key)};
|
return {id: key, name: players.get(key)};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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() {
|
function initMessageHandlers() {
|
||||||
Messaging.addEventListener(["Okaeri"], function(o) {
|
Messaging.addEventListener(["Okaeri"], function(o) {enterAll(o.room);});
|
||||||
players.insertAll(o.room);
|
Messaging.addEventListener(["Welcome"], function(o) {enterAll(o.room);});
|
||||||
});
|
Messaging.addEventListener(["LogIn"], function(o) {enterPlayer(o.from, o.as);});
|
||||||
Messaging.addEventListener(["Welcome"], function(o) {
|
Messaging.addEventListener(["LogOut"], function(o) {players.remove(o.from);});
|
||||||
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);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
14
js/Table.js
14
js/Table.js
|
@ -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 {
|
||||||
|
|
Loading…
Reference in a new issue