Skip to content

Commit

Permalink
change semantics of enabling/disabling events
Browse files Browse the repository at this point in the history
- all events are always available within game logic in the Events API
- enabling / disabling events merely affects whether the client can trigger them directly
  • Loading branch information
nicolodavis committed Nov 9, 2018
1 parent 992416a commit 53473ef
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 81 deletions.
3 changes: 3 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ endTurn({ next: playerID })
endTurnIf: () => ({ next: playerID })
```

6. The semantics of enabling / disabling events has changed
a bit: see https://boardgame.io/#/events for more details.

## v0.26.3

#### Features
Expand Down
51 changes: 37 additions & 14 deletions docs/events.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,6 @@ The default behavior is to increment `ctx.turn` by `1`
and advance `currentPlayer` to the next player according
to the configured turn order (the default being a round-robin).

This event is enabled by default. To disable this event,
pass `endTurn: false` inside your `flow` section. Note that
turns can still end if you use `endTurnIf` or `movesPerTurn`.
Disabling the event merely prevents you from explicitly
triggering it.

`endTurn` also accepts an argument, which (if provided)
switches the turn to the specified player.

Expand All @@ -31,10 +25,6 @@ is orthogonal to a player turn (i.e. you can end the phase
many times within a single turn, or you can have many
turns within a single phase).

To disable this event, pass `endPhase: false` inside your
`flow` section. Note that phases can still end if you use
`endPhaseIf`.

`endPhase` also accepts an argument, which (if provided)
switches the phase to the phase specified.

Expand Down Expand Up @@ -77,10 +67,6 @@ const opts = {
setActionPlayers(opts);
```

!> This event is not enabled by default and must be enabled
by setting `setActionPlayers: true` in the `flow` section
of your game.

### Triggering an event from a React client.

Events are available through `props` inside the
Expand Down Expand Up @@ -116,3 +102,40 @@ moves: {
};
}
```

### Enabling / Disabling events

An important point to note is that not all events are
enabled on the client, and some need to be explicitly
enabled.

The following table describes the defaults:

| Event | Default |
| :--------------: | :-----: |
| endTurn | true |
| endPhase | true |
| endGame | false |
| setActionPlayers | false |

In order to enable an event, just add `eventName: true` to
your `flow` section.

```js
flow: {
endGame: true,
...
}
```

In order to disable an event, add `eventName: false`.

```js
flow: {
endPhase: false,
...
}
```

!> This doesn't apply to events in game logic, inside
which all events are always enabled.
3 changes: 1 addition & 2 deletions examples/react/turnorder/example-militia.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { Game } from 'boardgame.io/core';

const code = `{
flow: {
setActionPlayers: true,
startingPhase: 'play',
phases: {
Expand Down Expand Up @@ -54,7 +53,7 @@ export default {

game: Game({
flow: {
setActionPlayers: true,
endPhase: false,
startingPhase: 'play',

phases: {
Expand Down
2 changes: 1 addition & 1 deletion src/client/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ class _ClientImpl {
);

this.events = createEventDispatchers(
this.game.flow.eventNames,
this.game.flow.enabledEventNames,
this.store,
this.playerID,
this.credentials,
Expand Down
69 changes: 21 additions & 48 deletions src/client/client.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,7 @@

import { createStore } from 'redux';
import { CreateGameReducer } from '../core/reducer';
import {
Client,
GetOpts,
createEventDispatchers,
createMoveDispatchers,
} from './client';
import { Client, GetOpts, createMoveDispatchers } from './client';
import { Local } from './transport/local';
import { SocketIO } from './transport/socketio';
import { update, sync, makeMove, gameEvent } from '../core/action-creators';
Expand Down Expand Up @@ -193,68 +188,46 @@ test('accepts enhancer for store', () => {
expect(spyDispatcher.mock.calls).toHaveLength(1);
});

test('event dispatchers', () => {
{
describe('event dispatchers', () => {
test('default', () => {
const game = Game({});
const reducer = CreateGameReducer({ game, numPlayers: 2 });
const store = createStore(reducer);
const api = createEventDispatchers(game.flow.eventNames, store);
expect(Object.getOwnPropertyNames(api)).toEqual(['endTurn']);
expect(store.getState().ctx.turn).toBe(0);
api.endTurn();
expect(store.getState().ctx.turn).toBe(1);
}

{
const client = Client({ game });
expect(Object.keys(client.events)).toEqual(['endTurn']);
expect(client.getState().ctx.turn).toBe(0);
client.events.endTurn();
expect(client.getState().ctx.turn).toBe(1);
});

test('all events', () => {
const game = Game({
flow: {
endPhase: true,
endGame: true,
setActionPlayers: true,
},
});
const reducer = CreateGameReducer({ game, numPlayers: 2 });
const store = createStore(reducer);
const api = createEventDispatchers(game.flow.eventNames, store);
expect(Object.getOwnPropertyNames(api)).toEqual([
const client = Client({ game });
expect(Object.keys(client.events)).toEqual([
'endTurn',
'endPhase',
'endGame',
'setActionPlayers',
]);
expect(store.getState().ctx.turn).toBe(0);
api.endTurn();
expect(store.getState().ctx.turn).toBe(1);
}
expect(client.getState().ctx.turn).toBe(0);
client.events.endTurn();
expect(client.getState().ctx.turn).toBe(1);
});

{
test('no events', () => {
const game = Game({
flow: {
endPhase: false,
endTurn: false,
},
});
const reducer = CreateGameReducer({ game, numPlayers: 2 });
const store = createStore(reducer);
const api = createEventDispatchers(game.flow.eventNames, store);
expect(Object.getOwnPropertyNames(api)).toEqual([]);
}

{
const game = Game({
flow: {
endPhase: true,
undoableMoves: ['A'],
},
});
const reducer = CreateGameReducer({ game, numPlayers: 2 });
const store = createStore(reducer);
const api = createEventDispatchers(game.flow.eventNames, store);
expect(Object.getOwnPropertyNames(api)).toEqual(['endTurn', 'endPhase']);
expect(store.getState().ctx.turn).toBe(0);
api.endTurn();
expect(store.getState().ctx.turn).toBe(1);
}
const client = Client({ game });
expect(Object.keys(client.events)).toEqual([]);
});
});

describe('move dispatchers', () => {
Expand Down
24 changes: 19 additions & 5 deletions src/core/flow.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ import * as logging from './logger';
* reducer will handle. Each function
* has the following signature:
* ({G, ctx}) => {G, ctx}
* @param {...object} enabledEvents - Map of eventName -> bool indicating
* which events are callable from the client
* 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
Expand All @@ -53,6 +56,7 @@ import * as logging from './logger';
export function Flow({
ctx,
events,
enabledEvents,
init,
processMove,
optimisticUpdate,
Expand All @@ -61,6 +65,7 @@ export function Flow({
}) {
if (!ctx) ctx = () => ({});
if (!events) events = {};
if (!enabledEvents) enabledEvents = {};
if (!init) init = state => state;
if (!processMove) processMove = state => state;
if (!canMakeMove) canMakeMove = () => true;
Expand Down Expand Up @@ -89,6 +94,7 @@ export function Flow({
canUndoMove,

eventNames: Object.getOwnPropertyNames(events),
enabledEventNames: Object.getOwnPropertyNames(enabledEvents),

processMove: (state, action) => {
return processMove(state, action, dispatch);
Expand Down Expand Up @@ -663,18 +669,25 @@ export function FlowWithPhases({
return conf.undoableMoves.includes(moveName);
};

const events = {
endTurn: endTurnEvent,
endPhase: endPhaseEvent,
endGame: endGameEvent,
setActionPlayers: SetActionPlayers,
};

let enabledEvents = {};
if (endTurn) {
enabledEvents['endTurn'] = endTurnEvent;
enabledEvents['endTurn'] = true;
}
if (endPhase) {
enabledEvents['endPhase'] = endPhaseEvent;
enabledEvents['endPhase'] = true;
}
if (endGame) {
enabledEvents['endGame'] = endGameEvent;
enabledEvents['endGame'] = true;
}
if (setActionPlayers) {
enabledEvents['setActionPlayers'] = SetActionPlayers;
enabledEvents['setActionPlayers'] = true;
}

return Flow({
Expand All @@ -700,7 +713,8 @@ export function FlowWithPhases({
}
return optimisticUpdate(G, ctx, action);
},
events: enabledEvents,
events,
enabledEvents,
processMove,
canMakeMove,
canUndoMove,
Expand Down
12 changes: 1 addition & 11 deletions src/core/turn-order.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ test('playOrder', () => {
});

describe('SetActionPlayers', () => {
const flow = FlowWithPhases({ setActionPlayers: true });
const flow = FlowWithPhases({});
const state = { ctx: flow.ctx(2) };

test('basic', () => {
Expand All @@ -217,10 +217,6 @@ describe('SetActionPlayers', () => {

test('once', () => {
const game = Game({
flow: {
setActionPlayers: true,
},

moves: {
B: (G, ctx) => {
ctx.events.setActionPlayers({ value: ['0', '1'], once: true });
Expand All @@ -243,10 +239,6 @@ describe('SetActionPlayers', () => {

test('allOthers', () => {
const game = Game({
flow: {
setActionPlayers: true,
},

moves: {
B: (G, ctx) => {
ctx.events.setActionPlayers({
Expand Down Expand Up @@ -279,8 +271,6 @@ describe('SetActionPlayers', () => {

test('militia', () => {
const game = Game({
flow: { setActionPlayers: true },

moves: {
playMilitia: (G, ctx) => {
// change which players need to act
Expand Down

0 comments on commit 53473ef

Please sign in to comment.