Skip to content

Commit

Permalink
make optimistic an option in long-form move syntax
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolodavis committed Sep 10, 2019
1 parent 3844837 commit 3a97a16
Show file tree
Hide file tree
Showing 4 changed files with 20 additions and 40 deletions.
31 changes: 0 additions & 31 deletions src/core/flow.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,13 @@ import * as logging from './logger';
* or from within moves.
* @param {...object} processMove - A function that's called whenever a move is made.
* (state, action, dispatch) => state.
* @param {...object} optimisticUpdate - (G, ctx, move) => boolean
* Control whether a move should
* be executed optimistically on
* the client while waiting for
* the result of execution from
* the server.
*/
export function Flow({
ctx,
events,
enabledEvents,
init,
processMove,
optimisticUpdate,
canUndoMove,
moveMap,
}) {
Expand All @@ -62,10 +55,6 @@ export function Flow({
if (!processMove) processMove = state => state;
if (!canUndoMove) canUndoMove = () => true;

if (optimisticUpdate === undefined) {
optimisticUpdate = () => true;
}

const dispatch = (state, action) => {
const { payload } = action;
if (events.hasOwnProperty(payload.type)) {
Expand Down Expand Up @@ -101,8 +90,6 @@ export function Flow({
return dispatch(state, action, dispatch);
},

optimisticUpdate,

canPlayerCallEvent: (G, ctx, playerID) => {
return (
ctx.currentPlayer == playerID && ctx.actionPlayers.includes(playerID)
Expand Down Expand Up @@ -166,13 +153,6 @@ export function Flow({
*
* @param {...object} setActionPlayers - Set to true to enable the `setActionPlayers` event.
*
* @param {...object} optimisticUpdate - (G, ctx, move) => boolean
* Control whether a move should
* be executed optimistically on
* the client while waiting for
* the result of execution from
* the server.
*
* @param {...object} phases - A map of phases in the game.
*
* {
Expand Down Expand Up @@ -201,7 +181,6 @@ export function FlowWithPhases({
endPhase,
endGame,
setActionPlayers,
optimisticUpdate,
getMove,
plugins,
}) {
Expand All @@ -218,9 +197,6 @@ export function FlowWithPhases({
if (setActionPlayers === undefined) {
setActionPlayers = false;
}
if (optimisticUpdate === undefined) {
optimisticUpdate = () => true;
}
if (plugins === undefined) {
plugins = [];
}
Expand Down Expand Up @@ -654,13 +630,6 @@ export function FlowWithPhases({
init: state => {
return startGame(state);
},
optimisticUpdate: (G, ctx, action) => {
// Some random code was executed.
if (ctx._random !== undefined && ctx._random.prngstate !== undefined) {
return false;
}
return optimisticUpdate(G, ctx, action);
},
events,
enabledEvents,
processMove,
Expand Down
1 change: 0 additions & 1 deletion src/core/flow.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ test('Flow', () => {
expect(flow.init({ a: 5 })).toMatchObject({ a: 5 });
expect(flow.canUndoMove()).toBe(true);
expect(flow.processMove({ b: 6 })).toMatchObject({ b: 6 });
expect(flow.optimisticUpdate()).toBe(true);
});

describe('phases', () => {
Expand Down
18 changes: 13 additions & 5 deletions src/core/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,11 @@ export function CreateGameReducer({ game, multiplayer }) {
return state;
}

// Don't run move on client if optimistic = false.
if (multiplayer && move.optimistic === false) {
return state;
}

// Disallow moves once the game is over.
if (state.ctx.gameover !== undefined) {
error(`cannot make move after game end`);
Expand Down Expand Up @@ -274,8 +279,9 @@ export function CreateGameReducer({ game, multiplayer }) {

// Process the move.
let G = game.processMove(state.G, action.payload, ctxWithAPI);

// The game declared the move as invalid.
if (G === INVALID_MOVE) {
// the game declared the move as invalid.
return state;
}

Expand All @@ -291,19 +297,21 @@ export function CreateGameReducer({ game, multiplayer }) {
logEntry.redact = true;
}

// don't call into events here
// Don't call into events here.
const newState = apiCtx.updateAndDetach(
{ ...state, deltalog: [logEntry] },
false
);
let ctx = newState.ctx;

// Undo changes to G if the move should not run on the client.
// Random API code was executed. If we are on the
// client, wait for the master response instead.
if (
multiplayer &&
!game.flow.optimisticUpdate(G, ctx, action.payload)
ctx._random !== undefined &&
ctx._random.prngstate !== undefined
) {
G = state.G;
return state;
}

state = { ...newState, G, ctx, _stateID: state._stateID + 1 };
Expand Down
10 changes: 7 additions & 3 deletions src/core/reducer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,14 @@ test('light client when multiplayer=true', () => {
}
});

test('optimisticUpdate', () => {
test('disable optimistic updates', () => {
const game = {
moves: { A: () => ({ A: true }) },
optimisticUpdate: () => false,
moves: {
A: {
impl: () => ({ A: true }),
optimistic: false,
},
},
};

{
Expand Down

0 comments on commit 3a97a16

Please sign in to comment.