UNPKG

2.91 kBJavaScriptView Raw
1/**
2 * So we have lots of actions that come to us from the nextActions queue in the reducer. Some of
3 * them can be dispatched as-is, but many of them require us to run an action creator function to
4 * e.g. decrypt or encrypt something as is appropriate. This middleware detects such actions and
5 * sees if we have a cooresponding action based on a simple naming convention.
6 *
7 * actions.SEED_RNG_DECRYPT => actions.seedRngDecryptAction
8 */
9
10export default function createGameActionMiddleware(actions) {
11 const actionMap = {};
12 Object.keys(actions).forEach(key => {
13 const value = actions[key];
14 if (typeof value !== "string" || key !== value) {
15 return;
16 }
17 const camelCase = value
18 .split("_")
19 .map(word => word[0].toUpperCase() + word.slice(1).toLowerCase())
20 .join("");
21 const actionCreator = camelCase[0].toLowerCase() + camelCase.slice(1);
22 if (actions[actionCreator]) {
23 actionMap[value] = actions[actionCreator];
24 }
25 });
26
27 /**
28 * two kinds of actions are allowed - you can either be a human that did an action on your turn or you can be a computer handling the most recent action in nextactions
29 */
30 function checkActionAllowed(state, action) {
31 // non-game actions are always allowed
32 if (!actions[action.type]) {
33 return;
34 }
35 // also if we don't have a turn order yet, nbd
36 if (!state.game || !state.game.turn) {
37 return;
38 }
39 const sender = action.agent || state.client.keys.id;
40 if (state.game.nextActions.length > 0) {
41 const queueUser = state.game.nextActions[0].playerId;
42 if (sender !== queueUser) {
43 throw new Error(
44 `queue wants user ${queueUser} but user ${sender} acted`
45 );
46 }
47 }
48 // no queue, check if it's an allowed action
49 else if (state.game.allowedActions[action.type] !== true) {
50 throw new Error(
51 `${sender} attempted to do non-allowed action ${action.type}`
52 );
53 } else if (state.game.turn !== sender) {
54 throw new Error(
55 `${sender} acted out of turn; it's ${state.game.turn}'s turn`
56 );
57 }
58 }
59
60 return function gameActionMiddleware(store) {
61 return next => {
62 return action => {
63 const state = store.getState();
64 let { dispatch, getState } = store;
65 checkActionAllowed(state, action);
66 if (
67 !state.client.loadingState &&
68 actionMap[action.type] &&
69 action._fromQueue &&
70 !action._dispatchedFromQueue
71 ) {
72 action = actionMap[action.type](action);
73 dispatch = action =>
74 store.dispatch({
75 ...action,
76 _fromQueue: true,
77 _dispatchedFromQueue: true
78 });
79 }
80 // implement thunk
81 if (typeof action === "function") {
82 return action(dispatch, getState);
83 }
84 return next(action);
85 };
86 };
87 };
88}