Skip to content

Commit 1e59401

Browse files
authored
Try to fix reordering of sets due to network lag (#178)
1 parent f5b6805 commit 1e59401

File tree

2 files changed

+38
-7
lines changed

2 files changed

+38
-7
lines changed

src/game.js

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ function processEvent(internalGameState, event) {
401401
updateBoard(internalGameState, event, cards);
402402
}
403403

404-
export function computeState(gameData, gameMode) {
404+
export function computeState(gameData, gameMode, newEvents = null) {
405405
if (!modes.hasOwnProperty(gameMode)) {
406406
throw new Error(`invalid gameMode: ${gameMode}`);
407407
}
@@ -440,10 +440,21 @@ export function computeState(gameData, gameMode) {
440440
};
441441

442442
if (gameData.events) {
443-
// Array.sort() is guaranteed to be stable in since around 2018
444-
const events = Object.values(gameData.events).sort(
445-
(e1, e2) => e1.time - e2.time
446-
);
443+
let events;
444+
// Array.sort() is guaranteed to be stable in since around 2018.
445+
if (newEvents?.size) {
446+
// Always sort new events (with approximate times) after old events.
447+
events = Object.entries(gameData.events)
448+
.sort(
449+
([k1, e1], [k2, e2]) =>
450+
newEvents.has(k1) - newEvents.has(k2) || e1.time - e2.time
451+
)
452+
.map(([k, e]) => e);
453+
} else {
454+
events = Object.values(gameData.events).sort(
455+
(e1, e2) => e1.time - e2.time
456+
);
457+
}
447458
for (const event of events) {
448459
processEvent(internalGameState, event);
449460
}

src/pages/GamePage.js

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ function GamePage({ match }) {
124124

125125
const [game, loadingGame] = useFirebaseRef(`games/${gameId}`);
126126
const [gameData, loadingGameData] = useFirebaseRef(`gameData/${gameId}`);
127+
const newEvents = useRef(new Set());
127128
const [hasNextGame] = useFirebaseRef(
128129
game?.status === "done" && (!game.users || !(user.id in game.users))
129130
? `games/${nextGameId}/status`
@@ -201,7 +202,11 @@ function GamePage({ match }) {
201202
lastKeptSet,
202203
} = useMemo(() => {
203204
if (!gameData) return {};
204-
const state = computeState({ ...gameData, random, deck }, gameMode);
205+
const state = computeState(
206+
{ ...gameData, random, deck },
207+
gameMode,
208+
newEvents.current
209+
);
205210
const { current, boardSize, findState, history } = state;
206211
const board = current.slice(0, boardSize);
207212
const answer = findSet(board, gameMode, findState);
@@ -251,14 +256,29 @@ function GamePage({ match }) {
251256
if (numHints) {
252257
firebase.database().ref(`gameData/${gameId}/hints`).remove();
253258
}
254-
firebase
259+
const eventRef = firebase
255260
.database()
256261
.ref(`gameData/${gameId}/events`)
257262
.push({
258263
...event,
259264
user: user.id,
260265
time: firebase.database.ServerValue.TIMESTAMP,
261266
});
267+
// Track "new" events that have approximate times. An event is new since
268+
// the time it was created until its time is updated from the server.
269+
// This happens when our callback is called the second time (the first
270+
// time it is called with the approximate time).
271+
const eventKey = eventRef.key;
272+
const timeRef = eventRef.child("time");
273+
newEvents.current.add(eventKey);
274+
let updateCount = 0;
275+
const timeUpdated = () => {
276+
if (++updateCount === 2) {
277+
newEvents.current.delete(eventKey);
278+
timeRef.off("value", timeUpdated);
279+
}
280+
};
281+
timeRef.on("value", timeUpdated);
262282
}
263283

264284
const hint = game.enableHint && answer ? answer.slice(0, numHints) : null;

0 commit comments

Comments
 (0)