@mnbroatch/boardgame.io 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (296) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +102 -0
  3. package/ai/package.json +7 -0
  4. package/client/package.json +7 -0
  5. package/core/package.json +7 -0
  6. package/debug/package.json +7 -0
  7. package/dist/boardgameio.es.js +14238 -0
  8. package/dist/boardgameio.js +14277 -0
  9. package/dist/boardgameio.min.js +16 -0
  10. package/dist/cjs/Debug-9d141c06.js +9586 -0
  11. package/dist/cjs/ai-e0e8a768.js +377 -0
  12. package/dist/cjs/ai.js +20 -0
  13. package/dist/cjs/client-76dec77b.js +258 -0
  14. package/dist/cjs/client-a22d7500.js +524 -0
  15. package/dist/cjs/client.js +26 -0
  16. package/dist/cjs/core.js +52 -0
  17. package/dist/cjs/debug.js +18 -0
  18. package/dist/cjs/filter-player-view-bb02e2f6.js +89 -0
  19. package/dist/cjs/initialize-267fcd69.js +61 -0
  20. package/dist/cjs/internal.js +25 -0
  21. package/dist/cjs/master-2904879d.js +320 -0
  22. package/dist/cjs/master.js +18 -0
  23. package/dist/cjs/multiplayer.js +23 -0
  24. package/dist/cjs/plugin-random-7425844d.js +229 -0
  25. package/dist/cjs/plugins.js +59 -0
  26. package/dist/cjs/react-native.js +182 -0
  27. package/dist/cjs/react.js +727 -0
  28. package/dist/cjs/reducer-16eec232.js +1203 -0
  29. package/dist/cjs/server.js +4087 -0
  30. package/dist/cjs/socketio-7a0837eb.js +478 -0
  31. package/dist/cjs/testing.js +30 -0
  32. package/dist/cjs/transport-b1874dfa.js +37 -0
  33. package/dist/cjs/turn-order-b2ff8740.js +1136 -0
  34. package/dist/cjs/util-fcfd8fb8.js +140 -0
  35. package/dist/esm/Debug-0141fe2d.js +9577 -0
  36. package/dist/esm/ai-5c06e761.js +371 -0
  37. package/dist/esm/ai.js +8 -0
  38. package/dist/esm/client-2e653027.js +522 -0
  39. package/dist/esm/client-5f57c3f2.js +255 -0
  40. package/dist/esm/client.js +16 -0
  41. package/dist/esm/core.js +40 -0
  42. package/dist/esm/debug.js +10 -0
  43. package/dist/esm/filter-player-view-2c6cc96f.js +87 -0
  44. package/dist/esm/initialize-11d626ca.js +59 -0
  45. package/dist/esm/internal.js +10 -0
  46. package/dist/esm/master-fa8f2e43.js +318 -0
  47. package/dist/esm/master.js +10 -0
  48. package/dist/esm/multiplayer.js +14 -0
  49. package/dist/esm/plugin-random-087f861e.js +226 -0
  50. package/dist/esm/plugins.js +55 -0
  51. package/dist/esm/react-native.js +173 -0
  52. package/dist/esm/react.js +716 -0
  53. package/dist/esm/reducer-c46da7e5.js +1198 -0
  54. package/dist/esm/socketio-c22ffa65.js +455 -0
  55. package/dist/esm/testing.js +26 -0
  56. package/dist/esm/transport-ce07b771.js +35 -0
  57. package/dist/esm/turn-order-376d315e.js +1091 -0
  58. package/dist/esm/util-b6147cef.js +135 -0
  59. package/dist/types/packages/ai.d.ts +5 -0
  60. package/dist/types/packages/client.d.ts +3 -0
  61. package/dist/types/packages/core.d.ts +5 -0
  62. package/dist/types/packages/debug.d.ts +2 -0
  63. package/dist/types/packages/internal.d.ts +8 -0
  64. package/dist/types/packages/master.d.ts +2 -0
  65. package/dist/types/packages/multiplayer.d.ts +3 -0
  66. package/dist/types/packages/plugins.d.ts +3 -0
  67. package/dist/types/packages/react-native.d.ts +2 -0
  68. package/dist/types/packages/react.d.ts +3 -0
  69. package/dist/types/packages/server.d.ts +6 -0
  70. package/dist/types/packages/testing.d.ts +1 -0
  71. package/dist/types/src/ai/ai.d.ts +53 -0
  72. package/dist/types/src/ai/ai.test.d.ts +1 -0
  73. package/dist/types/src/ai/bot.d.ts +40 -0
  74. package/dist/types/src/ai/mcts-bot.d.ts +60 -0
  75. package/dist/types/src/ai/random-bot.d.ts +27 -0
  76. package/dist/types/src/client/client.d.ts +104 -0
  77. package/dist/types/src/client/client.test.d.ts +1 -0
  78. package/dist/types/src/client/debug/tests/debug.test.d.ts +1 -0
  79. package/dist/types/src/client/manager.d.ts +61 -0
  80. package/dist/types/src/client/react.d.ts +75 -0
  81. package/dist/types/src/client/react.ssr.test.d.ts +4 -0
  82. package/dist/types/src/client/react.test.d.ts +1 -0
  83. package/dist/types/src/client/transport/dummy.d.ts +18 -0
  84. package/dist/types/src/client/transport/local.d.ts +59 -0
  85. package/dist/types/src/client/transport/local.test.d.ts +1 -0
  86. package/dist/types/src/client/transport/socketio.d.ts +45 -0
  87. package/dist/types/src/client/transport/socketio.test.d.ts +1 -0
  88. package/dist/types/src/client/transport/transport.d.ts +50 -0
  89. package/dist/types/src/client/transport/transport.test.d.ts +1 -0
  90. package/dist/types/src/core/action-creators.d.ts +144 -0
  91. package/dist/types/src/core/action-types.d.ts +10 -0
  92. package/dist/types/src/core/backwards-compatibility.d.ts +12 -0
  93. package/dist/types/src/core/constants.d.ts +6 -0
  94. package/dist/types/src/core/errors.d.ts +15 -0
  95. package/dist/types/src/core/flow.d.ts +28 -0
  96. package/dist/types/src/core/flow.test.d.ts +1 -0
  97. package/dist/types/src/core/game-methods.d.ts +9 -0
  98. package/dist/types/src/core/game.d.ts +26 -0
  99. package/dist/types/src/core/game.test.d.ts +1 -0
  100. package/dist/types/src/core/initialize.d.ts +9 -0
  101. package/dist/types/src/core/logger.d.ts +2 -0
  102. package/dist/types/src/core/player-view.d.ts +7 -0
  103. package/dist/types/src/core/player-view.test.d.ts +1 -0
  104. package/dist/types/src/core/reducer.d.ts +155 -0
  105. package/dist/types/src/core/reducer.test.d.ts +1 -0
  106. package/dist/types/src/core/turn-order.d.ts +179 -0
  107. package/dist/types/src/core/turn-order.test.d.ts +8 -0
  108. package/dist/types/src/lobby/client.d.ts +194 -0
  109. package/dist/types/src/lobby/client.test.d.ts +1 -0
  110. package/dist/types/src/lobby/connection.d.ts +44 -0
  111. package/dist/types/src/lobby/connection.test.d.ts +1 -0
  112. package/dist/types/src/lobby/create-match-form.d.ts +26 -0
  113. package/dist/types/src/lobby/login-form.d.ts +23 -0
  114. package/dist/types/src/lobby/match-instance.d.ts +31 -0
  115. package/dist/types/src/lobby/react.d.ts +113 -0
  116. package/dist/types/src/lobby/react.ssr.test.d.ts +4 -0
  117. package/dist/types/src/lobby/react.test.d.ts +1 -0
  118. package/dist/types/src/master/filter-player-view.d.ts +96 -0
  119. package/dist/types/src/master/filter-player-view.test.d.ts +1 -0
  120. package/dist/types/src/master/master.d.ts +94 -0
  121. package/dist/types/src/master/master.test.d.ts +1 -0
  122. package/dist/types/src/plugins/events/events.d.ts +54 -0
  123. package/dist/types/src/plugins/events/events.test.d.ts +1 -0
  124. package/dist/types/src/plugins/main.d.ts +75 -0
  125. package/dist/types/src/plugins/main.test.d.ts +1 -0
  126. package/dist/types/src/plugins/plugin-events.d.ts +5 -0
  127. package/dist/types/src/plugins/plugin-immer.d.ts +7 -0
  128. package/dist/types/src/plugins/plugin-immer.test.d.ts +1 -0
  129. package/dist/types/src/plugins/plugin-log.d.ts +14 -0
  130. package/dist/types/src/plugins/plugin-log.test.d.ts +1 -0
  131. package/dist/types/src/plugins/plugin-player.d.ts +29 -0
  132. package/dist/types/src/plugins/plugin-player.test.d.ts +1 -0
  133. package/dist/types/src/plugins/plugin-random.d.ts +4 -0
  134. package/dist/types/src/plugins/plugin-serializable.d.ts +7 -0
  135. package/dist/types/src/plugins/plugin-serializable.test.d.ts +1 -0
  136. package/dist/types/src/plugins/random/random.alea.d.ts +19 -0
  137. package/dist/types/src/plugins/random/random.d.ts +54 -0
  138. package/dist/types/src/plugins/random/random.test.d.ts +1 -0
  139. package/dist/types/src/server/api.d.ts +13 -0
  140. package/dist/types/src/server/api.test.d.ts +1 -0
  141. package/dist/types/src/server/auth.d.ts +38 -0
  142. package/dist/types/src/server/auth.test.d.ts +1 -0
  143. package/dist/types/src/server/cors.d.ts +4 -0
  144. package/dist/types/src/server/cors.test.d.ts +1 -0
  145. package/dist/types/src/server/db/base.d.ts +192 -0
  146. package/dist/types/src/server/db/flatfile.d.ts +44 -0
  147. package/dist/types/src/server/db/flatfile.test.d.ts +1 -0
  148. package/dist/types/src/server/db/index.d.ts +4 -0
  149. package/dist/types/src/server/db/index.test.d.ts +1 -0
  150. package/dist/types/src/server/db/inmemory.d.ts +43 -0
  151. package/dist/types/src/server/db/inmemory.test.d.ts +1 -0
  152. package/dist/types/src/server/db/localstorage.d.ts +7 -0
  153. package/dist/types/src/server/db/localstorage.test.d.ts +1 -0
  154. package/dist/types/src/server/index.d.ts +68 -0
  155. package/dist/types/src/server/index.test.d.ts +1 -0
  156. package/dist/types/src/server/transport/pubsub/generic-pub-sub.d.ts +6 -0
  157. package/dist/types/src/server/transport/pubsub/in-memory-pub-sub.d.ts +7 -0
  158. package/dist/types/src/server/transport/pubsub/in-memory-pub-sub.test.d.ts +1 -0
  159. package/dist/types/src/server/transport/socketio-simultaneous.test.d.ts +1 -0
  160. package/dist/types/src/server/transport/socketio.d.ts +65 -0
  161. package/dist/types/src/server/transport/socketio.test.d.ts +1 -0
  162. package/dist/types/src/server/util.d.ts +35 -0
  163. package/dist/types/src/testing/mock-random.d.ts +15 -0
  164. package/dist/types/src/testing/mock-random.test.d.ts +1 -0
  165. package/dist/types/src/types.d.ts +387 -0
  166. package/internal/package.json +7 -0
  167. package/master/package.json +7 -0
  168. package/multiplayer/package.json +7 -0
  169. package/package.json +211 -0
  170. package/plugins/package.json +7 -0
  171. package/react/package.json +7 -0
  172. package/react-native/package.json +7 -0
  173. package/server/package.json +6 -0
  174. package/src/ai/ai.test.ts +433 -0
  175. package/src/ai/ai.ts +84 -0
  176. package/src/ai/bot.ts +122 -0
  177. package/src/ai/mcts-bot.ts +331 -0
  178. package/src/ai/random-bot.ts +20 -0
  179. package/src/client/client.test.ts +993 -0
  180. package/src/client/client.ts +588 -0
  181. package/src/client/debug/Debug.svelte +239 -0
  182. package/src/client/debug/Menu.svelte +65 -0
  183. package/src/client/debug/ai/AI.svelte +215 -0
  184. package/src/client/debug/ai/Options.svelte +48 -0
  185. package/src/client/debug/info/Info.svelte +22 -0
  186. package/src/client/debug/info/Item.svelte +24 -0
  187. package/src/client/debug/log/Log.svelte +157 -0
  188. package/src/client/debug/log/LogEvent.svelte +149 -0
  189. package/src/client/debug/log/LogMetadata.svelte +7 -0
  190. package/src/client/debug/log/PhaseMarker.svelte +27 -0
  191. package/src/client/debug/log/TurnMarker.svelte +23 -0
  192. package/src/client/debug/main/ClientSwitcher.svelte +59 -0
  193. package/src/client/debug/main/Controls.svelte +58 -0
  194. package/src/client/debug/main/Hotkey.svelte +84 -0
  195. package/src/client/debug/main/InteractiveFunction.svelte +85 -0
  196. package/src/client/debug/main/Main.svelte +121 -0
  197. package/src/client/debug/main/Move.svelte +68 -0
  198. package/src/client/debug/main/PlayerInfo.svelte +70 -0
  199. package/src/client/debug/mcts/Action.svelte +22 -0
  200. package/src/client/debug/mcts/MCTS.svelte +78 -0
  201. package/src/client/debug/mcts/Table.svelte +98 -0
  202. package/src/client/debug/tests/JSONTree.mock.svelte +3 -0
  203. package/src/client/debug/tests/debug.test.ts +183 -0
  204. package/src/client/debug/utils/shortcuts.js +50 -0
  205. package/src/client/debug/utils/shortcuts.test.js +49 -0
  206. package/src/client/manager.ts +177 -0
  207. package/src/client/react-native.js +136 -0
  208. package/src/client/react-native.test.js +229 -0
  209. package/src/client/react.ssr.test.tsx +24 -0
  210. package/src/client/react.test.tsx +213 -0
  211. package/src/client/react.tsx +192 -0
  212. package/src/client/transport/dummy.ts +19 -0
  213. package/src/client/transport/local.test.ts +353 -0
  214. package/src/client/transport/local.ts +230 -0
  215. package/src/client/transport/socketio.test.ts +328 -0
  216. package/src/client/transport/socketio.ts +210 -0
  217. package/src/client/transport/transport.test.ts +27 -0
  218. package/src/client/transport/transport.ts +95 -0
  219. package/src/core/action-creators.ts +159 -0
  220. package/src/core/action-types.ts +18 -0
  221. package/src/core/backwards-compatibility.ts +23 -0
  222. package/src/core/constants.ts +6 -0
  223. package/src/core/errors.ts +35 -0
  224. package/src/core/flow.test.ts +2433 -0
  225. package/src/core/flow.ts +897 -0
  226. package/src/core/game-methods.ts +9 -0
  227. package/src/core/game.test.ts +286 -0
  228. package/src/core/game.ts +114 -0
  229. package/src/core/initialize.ts +77 -0
  230. package/src/core/logger.test.js +90 -0
  231. package/src/core/logger.ts +18 -0
  232. package/src/core/player-view.test.ts +50 -0
  233. package/src/core/player-view.ts +39 -0
  234. package/src/core/reducer.test.ts +991 -0
  235. package/src/core/reducer.ts +532 -0
  236. package/src/core/turn-order.test.ts +1123 -0
  237. package/src/core/turn-order.ts +473 -0
  238. package/src/lobby/client.test.ts +385 -0
  239. package/src/lobby/client.ts +358 -0
  240. package/src/lobby/connection.test.ts +207 -0
  241. package/src/lobby/connection.ts +162 -0
  242. package/src/lobby/create-match-form.tsx +122 -0
  243. package/src/lobby/login-form.tsx +75 -0
  244. package/src/lobby/match-instance.tsx +135 -0
  245. package/src/lobby/react.ssr.test.tsx +22 -0
  246. package/src/lobby/react.test.tsx +594 -0
  247. package/src/lobby/react.tsx +402 -0
  248. package/src/master/filter-player-view.test.ts +381 -0
  249. package/src/master/filter-player-view.ts +102 -0
  250. package/src/master/master.test.ts +1068 -0
  251. package/src/master/master.ts +492 -0
  252. package/src/plugins/events/events.test.ts +108 -0
  253. package/src/plugins/events/events.ts +209 -0
  254. package/src/plugins/main.test.ts +411 -0
  255. package/src/plugins/main.ts +314 -0
  256. package/src/plugins/plugin-events.ts +40 -0
  257. package/src/plugins/plugin-immer.test.ts +86 -0
  258. package/src/plugins/plugin-immer.ts +37 -0
  259. package/src/plugins/plugin-log.test.ts +37 -0
  260. package/src/plugins/plugin-log.ts +40 -0
  261. package/src/plugins/plugin-player.test.ts +172 -0
  262. package/src/plugins/plugin-player.ts +100 -0
  263. package/src/plugins/plugin-random.ts +40 -0
  264. package/src/plugins/plugin-serializable.test.ts +40 -0
  265. package/src/plugins/plugin-serializable.ts +55 -0
  266. package/src/plugins/random/random.alea.ts +109 -0
  267. package/src/plugins/random/random.test.ts +167 -0
  268. package/src/plugins/random/random.ts +198 -0
  269. package/src/server/api.test.ts +1699 -0
  270. package/src/server/api.ts +527 -0
  271. package/src/server/auth.test.ts +275 -0
  272. package/src/server/auth.ts +89 -0
  273. package/src/server/cors.test.ts +121 -0
  274. package/src/server/cors.ts +7 -0
  275. package/src/server/db/base.ts +296 -0
  276. package/src/server/db/flatfile.test.ts +221 -0
  277. package/src/server/db/flatfile.ts +228 -0
  278. package/src/server/db/index.test.ts +8 -0
  279. package/src/server/db/index.ts +12 -0
  280. package/src/server/db/inmemory.test.ts +143 -0
  281. package/src/server/db/inmemory.ts +143 -0
  282. package/src/server/db/localstorage.test.ts +73 -0
  283. package/src/server/db/localstorage.ts +44 -0
  284. package/src/server/index.test.ts +265 -0
  285. package/src/server/index.ts +175 -0
  286. package/src/server/transport/pubsub/generic-pub-sub.ts +11 -0
  287. package/src/server/transport/pubsub/in-memory-pub-sub.test.ts +47 -0
  288. package/src/server/transport/pubsub/in-memory-pub-sub.ts +28 -0
  289. package/src/server/transport/socketio-simultaneous.test.ts +603 -0
  290. package/src/server/transport/socketio.test.ts +303 -0
  291. package/src/server/transport/socketio.ts +279 -0
  292. package/src/server/util.ts +85 -0
  293. package/src/testing/mock-random.test.ts +45 -0
  294. package/src/testing/mock-random.ts +27 -0
  295. package/src/types.ts +511 -0
  296. package/testing/package.json +7 -0
@@ -0,0 +1,716 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { C as Client$1 } from './client-2e653027.js';
4
+ import Cookies from 'react-cookies';
5
+ import { M as MCTSBot } from './ai-5c06e761.js';
6
+ import { S as SocketIO, L as Local } from './socketio-c22ffa65.js';
7
+ import { L as LobbyClient } from './client-5f57c3f2.js';
8
+ import 'nanoid/non-secure';
9
+ import './Debug-0141fe2d.js';
10
+ import './turn-order-376d315e.js';
11
+ import 'immer';
12
+ import './plugin-random-087f861e.js';
13
+ import 'lodash.isplainobject';
14
+ import 'flatted';
15
+ import './reducer-c46da7e5.js';
16
+ import 'rfc6902';
17
+ import 'redux';
18
+ import './initialize-11d626ca.js';
19
+ import './transport-ce07b771.js';
20
+ import 'setimmediate';
21
+ import './util-b6147cef.js';
22
+ import './master-fa8f2e43.js';
23
+ import './filter-player-view-2c6cc96f.js';
24
+ import 'socket.io-client';
25
+
26
+ /*
27
+ * Copyright 2017 The boardgame.io Authors
28
+ *
29
+ * Use of this source code is governed by a MIT-style
30
+ * license that can be found in the LICENSE file or at
31
+ * https://opensource.org/licenses/MIT.
32
+ */
33
+ /**
34
+ * Client
35
+ *
36
+ * boardgame.io React client.
37
+ *
38
+ * @param {...object} game - The return value of `Game`.
39
+ * @param {...object} numPlayers - The number of players.
40
+ * @param {...object} board - The React component for the game.
41
+ * @param {...object} loading - (optional) The React component for the loading state.
42
+ * @param {...object} multiplayer - Set to a falsy value or a transportFactory, e.g., SocketIO()
43
+ * @param {...object} debug - Enables the Debug UI.
44
+ * @param {...object} enhancer - Optional enhancer to send to the Redux store
45
+ *
46
+ * Returns:
47
+ * A React component that wraps board and provides an
48
+ * API through props for it to interact with the framework
49
+ * and dispatch actions such as MAKE_MOVE, GAME_EVENT, RESET,
50
+ * UNDO and REDO.
51
+ */
52
+ function Client(opts) {
53
+ var _a;
54
+ const { game, numPlayers, board, multiplayer, enhancer } = opts;
55
+ let { loading, debug } = opts;
56
+ // Component that is displayed before the client has synced
57
+ // with the game master.
58
+ if (loading === undefined) {
59
+ const Loading = () => React.createElement("div", { className: "bgio-loading" }, "connecting...");
60
+ loading = Loading;
61
+ }
62
+ /*
63
+ * WrappedBoard
64
+ *
65
+ * The main React component that wraps the passed in
66
+ * board component and adds the API to its props.
67
+ */
68
+ return _a = class WrappedBoard extends React.Component {
69
+ constructor(props) {
70
+ super(props);
71
+ if (debug === undefined) {
72
+ debug = props.debug;
73
+ }
74
+ this.client = Client$1({
75
+ game,
76
+ debug,
77
+ numPlayers,
78
+ multiplayer,
79
+ matchID: props.matchID,
80
+ playerID: props.playerID,
81
+ credentials: props.credentials,
82
+ enhancer,
83
+ });
84
+ }
85
+ componentDidMount() {
86
+ this.unsubscribe = this.client.subscribe(() => this.forceUpdate());
87
+ this.client.start();
88
+ }
89
+ componentWillUnmount() {
90
+ this.client.stop();
91
+ this.unsubscribe();
92
+ }
93
+ componentDidUpdate(prevProps) {
94
+ if (this.props.matchID != prevProps.matchID) {
95
+ this.client.updateMatchID(this.props.matchID);
96
+ }
97
+ if (this.props.playerID != prevProps.playerID) {
98
+ this.client.updatePlayerID(this.props.playerID);
99
+ }
100
+ if (this.props.credentials != prevProps.credentials) {
101
+ this.client.updateCredentials(this.props.credentials);
102
+ }
103
+ }
104
+ render() {
105
+ const state = this.client.getState();
106
+ if (state === null) {
107
+ return React.createElement(loading);
108
+ }
109
+ let _board = null;
110
+ if (board) {
111
+ _board = React.createElement(board, {
112
+ ...state,
113
+ ...this.props,
114
+ isMultiplayer: !!multiplayer,
115
+ moves: this.client.moves,
116
+ events: this.client.events,
117
+ matchID: this.client.matchID,
118
+ playerID: this.client.playerID,
119
+ reset: this.client.reset,
120
+ undo: this.client.undo,
121
+ redo: this.client.redo,
122
+ log: this.client.log,
123
+ matchData: this.client.matchData,
124
+ sendChatMessage: this.client.sendChatMessage,
125
+ chatMessages: this.client.chatMessages,
126
+ });
127
+ }
128
+ return React.createElement("div", { className: "bgio-client" }, _board);
129
+ }
130
+ },
131
+ _a.propTypes = {
132
+ // The ID of a game to connect to.
133
+ // Only relevant in multiplayer.
134
+ matchID: PropTypes.string,
135
+ // The ID of the player associated with this client.
136
+ // Only relevant in multiplayer.
137
+ playerID: PropTypes.string,
138
+ // This client's authentication credentials.
139
+ // Only relevant in multiplayer.
140
+ credentials: PropTypes.string,
141
+ // Enable / disable the Debug UI.
142
+ debug: PropTypes.any,
143
+ },
144
+ _a.defaultProps = {
145
+ matchID: 'default',
146
+ playerID: null,
147
+ credentials: null,
148
+ debug: true,
149
+ },
150
+ _a;
151
+ }
152
+
153
+ /*
154
+ * Copyright 2018 The boardgame.io Authors
155
+ *
156
+ * Use of this source code is governed by a MIT-style
157
+ * license that can be found in the LICENSE file or at
158
+ * https://opensource.org/licenses/MIT.
159
+ */
160
+ class _LobbyConnectionImpl {
161
+ constructor({ server, gameComponents, playerName, playerCredentials, }) {
162
+ this.client = new LobbyClient({ server });
163
+ this.gameComponents = gameComponents;
164
+ this.playerName = playerName || 'Visitor';
165
+ this.playerCredentials = playerCredentials;
166
+ this.matches = [];
167
+ }
168
+ async refresh() {
169
+ try {
170
+ this.matches = [];
171
+ const games = await this.client.listGames();
172
+ for (const game of games) {
173
+ if (!this._getGameComponents(game))
174
+ continue;
175
+ const { matches } = await this.client.listMatches(game);
176
+ this.matches.push(...matches);
177
+ }
178
+ }
179
+ catch (error) {
180
+ throw new Error('failed to retrieve list of matches (' + error + ')');
181
+ }
182
+ }
183
+ _getMatchInstance(matchID) {
184
+ for (const inst of this.matches) {
185
+ if (inst['matchID'] === matchID)
186
+ return inst;
187
+ }
188
+ }
189
+ _getGameComponents(gameName) {
190
+ for (const comp of this.gameComponents) {
191
+ if (comp.game.name === gameName)
192
+ return comp;
193
+ }
194
+ }
195
+ _findPlayer(playerName) {
196
+ for (const inst of this.matches) {
197
+ if (inst.players.some((player) => player.name === playerName))
198
+ return inst;
199
+ }
200
+ }
201
+ async join(gameName, matchID, playerID) {
202
+ try {
203
+ let inst = this._findPlayer(this.playerName);
204
+ if (inst) {
205
+ throw new Error('player has already joined ' + inst.matchID);
206
+ }
207
+ inst = this._getMatchInstance(matchID);
208
+ if (!inst) {
209
+ throw new Error('game instance ' + matchID + ' not found');
210
+ }
211
+ const json = await this.client.joinMatch(gameName, matchID, {
212
+ playerID,
213
+ playerName: this.playerName,
214
+ });
215
+ inst.players[Number.parseInt(playerID)].name = this.playerName;
216
+ this.playerCredentials = json.playerCredentials;
217
+ }
218
+ catch (error) {
219
+ throw new Error('failed to join match ' + matchID + ' (' + error + ')');
220
+ }
221
+ }
222
+ async leave(gameName, matchID) {
223
+ try {
224
+ const inst = this._getMatchInstance(matchID);
225
+ if (!inst)
226
+ throw new Error('match instance not found');
227
+ for (const player of inst.players) {
228
+ if (player.name === this.playerName) {
229
+ await this.client.leaveMatch(gameName, matchID, {
230
+ playerID: player.id.toString(),
231
+ credentials: this.playerCredentials,
232
+ });
233
+ delete player.name;
234
+ delete this.playerCredentials;
235
+ return;
236
+ }
237
+ }
238
+ throw new Error('player not found in match');
239
+ }
240
+ catch (error) {
241
+ throw new Error('failed to leave match ' + matchID + ' (' + error + ')');
242
+ }
243
+ }
244
+ async disconnect() {
245
+ const inst = this._findPlayer(this.playerName);
246
+ if (inst) {
247
+ await this.leave(inst.gameName, inst.matchID);
248
+ }
249
+ this.matches = [];
250
+ this.playerName = 'Visitor';
251
+ }
252
+ async create(gameName, numPlayers) {
253
+ try {
254
+ const comp = this._getGameComponents(gameName);
255
+ if (!comp)
256
+ throw new Error('game not found');
257
+ if (numPlayers < comp.game.minPlayers ||
258
+ numPlayers > comp.game.maxPlayers)
259
+ throw new Error('invalid number of players ' + numPlayers);
260
+ await this.client.createMatch(gameName, { numPlayers });
261
+ }
262
+ catch (error) {
263
+ throw new Error('failed to create match for ' + gameName + ' (' + error + ')');
264
+ }
265
+ }
266
+ }
267
+ /**
268
+ * LobbyConnection
269
+ *
270
+ * Lobby model.
271
+ *
272
+ * @param {string} server - '<host>:<port>' of the server.
273
+ * @param {Array} gameComponents - A map of Board and Game objects for the supported games.
274
+ * @param {string} playerName - The name of the player.
275
+ * @param {string} playerCredentials - The credentials currently used by the player, if any.
276
+ *
277
+ * Returns:
278
+ * A JS object that synchronizes the list of running game instances with the server and provides an API to create/join/start instances.
279
+ */
280
+ function LobbyConnection(opts) {
281
+ return new _LobbyConnectionImpl(opts);
282
+ }
283
+
284
+ /*
285
+ * Copyright 2018 The boardgame.io Authors.
286
+ *
287
+ * Use of this source code is governed by a MIT-style
288
+ * license that can be found in the LICENSE file or at
289
+ * https://opensource.org/licenses/MIT.
290
+ */
291
+ class LobbyLoginForm extends React.Component {
292
+ constructor() {
293
+ super(...arguments);
294
+ this.state = {
295
+ playerName: this.props.playerName,
296
+ nameErrorMsg: '',
297
+ };
298
+ this.onClickEnter = () => {
299
+ if (this.state.playerName === '')
300
+ return;
301
+ this.props.onEnter(this.state.playerName);
302
+ };
303
+ this.onKeyPress = (event) => {
304
+ if (event.key === 'Enter') {
305
+ this.onClickEnter();
306
+ }
307
+ };
308
+ this.onChangePlayerName = (event) => {
309
+ const name = event.target.value.trim();
310
+ this.setState({
311
+ playerName: name,
312
+ nameErrorMsg: name.length > 0 ? '' : 'empty player name',
313
+ });
314
+ };
315
+ }
316
+ render() {
317
+ return (React.createElement("div", null,
318
+ React.createElement("p", { className: "phase-title" }, "Choose a player name:"),
319
+ React.createElement("input", { type: "text", value: this.state.playerName, onChange: this.onChangePlayerName, onKeyPress: this.onKeyPress }),
320
+ React.createElement("span", { className: "buttons" },
321
+ React.createElement("button", { className: "buttons", onClick: this.onClickEnter }, "Enter")),
322
+ React.createElement("br", null),
323
+ React.createElement("span", { className: "error-msg" },
324
+ this.state.nameErrorMsg,
325
+ React.createElement("br", null))));
326
+ }
327
+ }
328
+ LobbyLoginForm.defaultProps = {
329
+ playerName: '',
330
+ };
331
+
332
+ /*
333
+ * Copyright 2018 The boardgame.io Authors.
334
+ *
335
+ * Use of this source code is governed by a MIT-style
336
+ * license that can be found in the LICENSE file or at
337
+ * https://opensource.org/licenses/MIT.
338
+ */
339
+ class LobbyMatchInstance extends React.Component {
340
+ constructor() {
341
+ super(...arguments);
342
+ this._createSeat = (player) => {
343
+ return player.name || '[free]';
344
+ };
345
+ this._createButtonJoin = (inst, seatId) => (React.createElement("button", { key: 'button-join-' + inst.matchID, onClick: () => this.props.onClickJoin(inst.gameName, inst.matchID, '' + seatId) }, "Join"));
346
+ this._createButtonLeave = (inst) => (React.createElement("button", { key: 'button-leave-' + inst.matchID, onClick: () => this.props.onClickLeave(inst.gameName, inst.matchID) }, "Leave"));
347
+ this._createButtonPlay = (inst, seatId) => (React.createElement("button", { key: 'button-play-' + inst.matchID, onClick: () => this.props.onClickPlay(inst.gameName, {
348
+ matchID: inst.matchID,
349
+ playerID: '' + seatId,
350
+ numPlayers: inst.players.length,
351
+ }) }, "Play"));
352
+ this._createButtonSpectate = (inst) => (React.createElement("button", { key: 'button-spectate-' + inst.matchID, onClick: () => this.props.onClickPlay(inst.gameName, {
353
+ matchID: inst.matchID,
354
+ numPlayers: inst.players.length,
355
+ }) }, "Spectate"));
356
+ this._createInstanceButtons = (inst) => {
357
+ const playerSeat = inst.players.find((player) => player.name === this.props.playerName);
358
+ const freeSeat = inst.players.find((player) => !player.name);
359
+ if (playerSeat && freeSeat) {
360
+ // already seated: waiting for match to start
361
+ return this._createButtonLeave(inst);
362
+ }
363
+ if (freeSeat) {
364
+ // at least 1 seat is available
365
+ return this._createButtonJoin(inst, freeSeat.id);
366
+ }
367
+ // match is full
368
+ if (playerSeat) {
369
+ return (React.createElement("div", null, [
370
+ this._createButtonPlay(inst, playerSeat.id),
371
+ this._createButtonLeave(inst),
372
+ ]));
373
+ }
374
+ // allow spectating
375
+ return this._createButtonSpectate(inst);
376
+ };
377
+ }
378
+ render() {
379
+ const match = this.props.match;
380
+ let status = 'OPEN';
381
+ if (!match.players.some((player) => !player.name)) {
382
+ status = 'RUNNING';
383
+ }
384
+ return (React.createElement("tr", { key: 'line-' + match.matchID },
385
+ React.createElement("td", { key: 'cell-name-' + match.matchID }, match.gameName),
386
+ React.createElement("td", { key: 'cell-status-' + match.matchID }, status),
387
+ React.createElement("td", { key: 'cell-seats-' + match.matchID }, match.players.map((player) => this._createSeat(player)).join(', ')),
388
+ React.createElement("td", { key: 'cell-buttons-' + match.matchID }, this._createInstanceButtons(match))));
389
+ }
390
+ }
391
+
392
+ /*
393
+ * Copyright 2018 The boardgame.io Authors.
394
+ *
395
+ * Use of this source code is governed by a MIT-style
396
+ * license that can be found in the LICENSE file or at
397
+ * https://opensource.org/licenses/MIT.
398
+ */
399
+ class LobbyCreateMatchForm extends React.Component {
400
+ constructor(props) {
401
+ super(props);
402
+ this.state = {
403
+ selectedGame: 0,
404
+ numPlayers: 2,
405
+ };
406
+ this._createGameNameOption = (game, idx) => {
407
+ return (React.createElement("option", { key: 'name-option-' + idx, value: idx }, game.game.name));
408
+ };
409
+ this._createNumPlayersOption = (idx) => {
410
+ return (React.createElement("option", { key: 'num-option-' + idx, value: idx }, idx));
411
+ };
412
+ this._createNumPlayersRange = (game) => {
413
+ return Array.from({ length: game.maxPlayers + 1 })
414
+ .map((_, i) => i)
415
+ .slice(game.minPlayers);
416
+ };
417
+ this.onChangeNumPlayers = (event) => {
418
+ this.setState({
419
+ numPlayers: Number.parseInt(event.target.value),
420
+ });
421
+ };
422
+ this.onChangeSelectedGame = (event) => {
423
+ const idx = Number.parseInt(event.target.value);
424
+ this.setState({
425
+ selectedGame: idx,
426
+ numPlayers: this.props.games[idx].game.minPlayers,
427
+ });
428
+ };
429
+ this.onClickCreate = () => {
430
+ this.props.createMatch(this.props.games[this.state.selectedGame].game.name, this.state.numPlayers);
431
+ };
432
+ /* fix min and max number of players */
433
+ for (const game of props.games) {
434
+ const matchDetails = game.game;
435
+ if (!matchDetails.minPlayers) {
436
+ matchDetails.minPlayers = 1;
437
+ }
438
+ if (!matchDetails.maxPlayers) {
439
+ matchDetails.maxPlayers = 4;
440
+ }
441
+ console.assert(matchDetails.maxPlayers >= matchDetails.minPlayers);
442
+ }
443
+ this.state = {
444
+ selectedGame: 0,
445
+ numPlayers: props.games[0].game.minPlayers,
446
+ };
447
+ }
448
+ render() {
449
+ return (React.createElement("div", null,
450
+ React.createElement("select", { value: this.state.selectedGame, onChange: (evt) => this.onChangeSelectedGame(evt) }, this.props.games.map((game, index) => this._createGameNameOption(game, index))),
451
+ React.createElement("span", null, "Players:"),
452
+ React.createElement("select", { value: this.state.numPlayers, onChange: this.onChangeNumPlayers }, this._createNumPlayersRange(this.props.games[this.state.selectedGame].game).map((number) => this._createNumPlayersOption(number))),
453
+ React.createElement("span", { className: "buttons" },
454
+ React.createElement("button", { onClick: this.onClickCreate }, "Create"))));
455
+ }
456
+ }
457
+
458
+ /*
459
+ * Copyright 2018 The boardgame.io Authors.
460
+ *
461
+ * Use of this source code is governed by a MIT-style
462
+ * license that can be found in the LICENSE file or at
463
+ * https://opensource.org/licenses/MIT.
464
+ */
465
+ var LobbyPhases;
466
+ (function (LobbyPhases) {
467
+ LobbyPhases["ENTER"] = "enter";
468
+ LobbyPhases["PLAY"] = "play";
469
+ LobbyPhases["LIST"] = "list";
470
+ })(LobbyPhases || (LobbyPhases = {}));
471
+ /**
472
+ * Lobby
473
+ *
474
+ * React lobby component.
475
+ *
476
+ * @param {Array} gameComponents - An array of Board and Game objects for the supported games.
477
+ * @param {string} lobbyServer - Address of the lobby server (for example 'localhost:8000').
478
+ * If not set, defaults to the server that served the page.
479
+ * @param {string} gameServer - Address of the game server (for example 'localhost:8001').
480
+ * If not set, defaults to the server that served the page.
481
+ * @param {function} clientFactory - Function that is used to create the game clients.
482
+ * @param {number} refreshInterval - Interval between server updates (default: 2000ms).
483
+ * @param {bool} debug - Enable debug information (default: false).
484
+ *
485
+ * Returns:
486
+ * A React component that provides a UI to create, list, join, leave, play or
487
+ * spectate matches (game instances).
488
+ */
489
+ class Lobby extends React.Component {
490
+ constructor(props) {
491
+ super(props);
492
+ this.state = {
493
+ phase: LobbyPhases.ENTER,
494
+ playerName: 'Visitor',
495
+ runningMatch: null,
496
+ errorMsg: '',
497
+ credentialStore: {},
498
+ };
499
+ this._createConnection = (props) => {
500
+ const name = this.state.playerName;
501
+ this.connection = LobbyConnection({
502
+ server: props.lobbyServer,
503
+ gameComponents: props.gameComponents,
504
+ playerName: name,
505
+ playerCredentials: this.state.credentialStore[name],
506
+ });
507
+ };
508
+ this._updateCredentials = (playerName, credentials) => {
509
+ this.setState((prevState) => {
510
+ // clone store or componentDidUpdate will not be triggered
511
+ const store = Object.assign({}, prevState.credentialStore);
512
+ store[playerName] = credentials;
513
+ return { credentialStore: store };
514
+ });
515
+ };
516
+ this._updateConnection = async () => {
517
+ await this.connection.refresh();
518
+ this.forceUpdate();
519
+ };
520
+ this._enterLobby = (playerName) => {
521
+ this._startRefreshInterval();
522
+ this.setState({ playerName, phase: LobbyPhases.LIST });
523
+ };
524
+ this._exitLobby = async () => {
525
+ this._clearRefreshInterval();
526
+ await this.connection.disconnect();
527
+ this.setState({ phase: LobbyPhases.ENTER, errorMsg: '' });
528
+ };
529
+ this._createMatch = async (gameName, numPlayers) => {
530
+ try {
531
+ await this.connection.create(gameName, numPlayers);
532
+ await this.connection.refresh();
533
+ // rerender
534
+ this.setState({});
535
+ }
536
+ catch (error) {
537
+ this.setState({ errorMsg: error.message });
538
+ }
539
+ };
540
+ this._joinMatch = async (gameName, matchID, playerID) => {
541
+ try {
542
+ await this.connection.join(gameName, matchID, playerID);
543
+ await this.connection.refresh();
544
+ this._updateCredentials(this.connection.playerName, this.connection.playerCredentials);
545
+ }
546
+ catch (error) {
547
+ this.setState({ errorMsg: error.message });
548
+ }
549
+ };
550
+ this._leaveMatch = async (gameName, matchID) => {
551
+ try {
552
+ await this.connection.leave(gameName, matchID);
553
+ await this.connection.refresh();
554
+ this._updateCredentials(this.connection.playerName, this.connection.playerCredentials);
555
+ }
556
+ catch (error) {
557
+ this.setState({ errorMsg: error.message });
558
+ }
559
+ };
560
+ this._startMatch = (gameName, matchOpts) => {
561
+ const gameCode = this.connection._getGameComponents(gameName);
562
+ if (!gameCode) {
563
+ this.setState({
564
+ errorMsg: 'game ' + gameName + ' not supported',
565
+ });
566
+ return;
567
+ }
568
+ let multiplayer = undefined;
569
+ if (matchOpts.numPlayers > 1) {
570
+ multiplayer = this.props.gameServer
571
+ ? SocketIO({ server: this.props.gameServer })
572
+ : SocketIO();
573
+ }
574
+ if (matchOpts.numPlayers == 1) {
575
+ const maxPlayers = gameCode.game.maxPlayers;
576
+ const bots = {};
577
+ for (let i = 1; i < maxPlayers; i++) {
578
+ bots[i + ''] = MCTSBot;
579
+ }
580
+ multiplayer = Local({ bots });
581
+ }
582
+ const app = this.props.clientFactory({
583
+ game: gameCode.game,
584
+ board: gameCode.board,
585
+ debug: this.props.debug,
586
+ multiplayer,
587
+ });
588
+ const match = {
589
+ app: app,
590
+ matchID: matchOpts.matchID,
591
+ playerID: matchOpts.numPlayers > 1 ? matchOpts.playerID : '0',
592
+ credentials: this.connection.playerCredentials,
593
+ };
594
+ this._clearRefreshInterval();
595
+ this.setState({ phase: LobbyPhases.PLAY, runningMatch: match });
596
+ };
597
+ this._exitMatch = () => {
598
+ this._startRefreshInterval();
599
+ this.setState({ phase: LobbyPhases.LIST, runningMatch: null });
600
+ };
601
+ this._getPhaseVisibility = (phase) => {
602
+ return this.state.phase !== phase ? 'hidden' : 'phase';
603
+ };
604
+ this.renderMatches = (matches, playerName) => {
605
+ return matches.map((match) => {
606
+ const { matchID, gameName, players } = match;
607
+ return (React.createElement(LobbyMatchInstance, { key: 'instance-' + matchID, match: { matchID, gameName, players: Object.values(players) }, playerName: playerName, onClickJoin: this._joinMatch, onClickLeave: this._leaveMatch, onClickPlay: this._startMatch }));
608
+ });
609
+ };
610
+ this._createConnection(this.props);
611
+ }
612
+ componentDidMount() {
613
+ const cookie = Cookies.load('lobbyState') || {};
614
+ if (cookie.phase && cookie.phase === LobbyPhases.PLAY) {
615
+ cookie.phase = LobbyPhases.LIST;
616
+ }
617
+ if (cookie.phase && cookie.phase !== LobbyPhases.ENTER) {
618
+ this._startRefreshInterval();
619
+ }
620
+ this.setState({
621
+ phase: cookie.phase || LobbyPhases.ENTER,
622
+ playerName: cookie.playerName || 'Visitor',
623
+ credentialStore: cookie.credentialStore || {},
624
+ });
625
+ }
626
+ componentDidUpdate(prevProps, prevState) {
627
+ const name = this.state.playerName;
628
+ const creds = this.state.credentialStore[name];
629
+ if (prevState.phase !== this.state.phase ||
630
+ prevState.credentialStore[name] !== creds ||
631
+ prevState.playerName !== name) {
632
+ this._createConnection(this.props);
633
+ this._updateConnection();
634
+ const cookie = {
635
+ phase: this.state.phase,
636
+ playerName: name,
637
+ credentialStore: this.state.credentialStore,
638
+ };
639
+ Cookies.save('lobbyState', cookie, { path: '/' });
640
+ }
641
+ if (prevProps.refreshInterval !== this.props.refreshInterval) {
642
+ this._startRefreshInterval();
643
+ }
644
+ }
645
+ componentWillUnmount() {
646
+ this._clearRefreshInterval();
647
+ }
648
+ _startRefreshInterval() {
649
+ this._clearRefreshInterval();
650
+ this._currentInterval = setInterval(this._updateConnection, this.props.refreshInterval);
651
+ }
652
+ _clearRefreshInterval() {
653
+ clearInterval(this._currentInterval);
654
+ }
655
+ render() {
656
+ const { gameComponents, renderer } = this.props;
657
+ const { errorMsg, playerName, phase, runningMatch } = this.state;
658
+ if (renderer) {
659
+ return renderer({
660
+ errorMsg,
661
+ gameComponents,
662
+ matches: this.connection.matches,
663
+ phase,
664
+ playerName,
665
+ runningMatch,
666
+ handleEnterLobby: this._enterLobby,
667
+ handleExitLobby: this._exitLobby,
668
+ handleCreateMatch: this._createMatch,
669
+ handleJoinMatch: this._joinMatch,
670
+ handleLeaveMatch: this._leaveMatch,
671
+ handleExitMatch: this._exitMatch,
672
+ handleRefreshMatches: this._updateConnection,
673
+ handleStartMatch: this._startMatch,
674
+ });
675
+ }
676
+ return (React.createElement("div", { id: "lobby-view", style: { padding: 50 } },
677
+ React.createElement("div", { className: this._getPhaseVisibility(LobbyPhases.ENTER) },
678
+ React.createElement(LobbyLoginForm, { key: playerName, playerName: playerName, onEnter: this._enterLobby })),
679
+ React.createElement("div", { className: this._getPhaseVisibility(LobbyPhases.LIST) },
680
+ React.createElement("p", null,
681
+ "Welcome, ",
682
+ playerName),
683
+ React.createElement("div", { className: "phase-title", id: "match-creation" },
684
+ React.createElement("span", null, "Create a match:"),
685
+ React.createElement(LobbyCreateMatchForm, { games: gameComponents, createMatch: this._createMatch })),
686
+ React.createElement("p", { className: "phase-title" }, "Join a match:"),
687
+ React.createElement("div", { id: "instances" },
688
+ React.createElement("table", null,
689
+ React.createElement("tbody", null, this.renderMatches(this.connection.matches, playerName))),
690
+ React.createElement("span", { className: "error-msg" },
691
+ errorMsg,
692
+ React.createElement("br", null))),
693
+ React.createElement("p", { className: "phase-title" }, "Matches that become empty are automatically deleted.")),
694
+ React.createElement("div", { className: this._getPhaseVisibility(LobbyPhases.PLAY) },
695
+ runningMatch && (React.createElement(runningMatch.app, { matchID: runningMatch.matchID, playerID: runningMatch.playerID, credentials: runningMatch.credentials })),
696
+ React.createElement("div", { className: "buttons", id: "match-exit" },
697
+ React.createElement("button", { onClick: this._exitMatch }, "Exit match"))),
698
+ React.createElement("div", { className: "buttons", id: "lobby-exit" },
699
+ React.createElement("button", { onClick: this._exitLobby }, "Exit lobby"))));
700
+ }
701
+ }
702
+ Lobby.propTypes = {
703
+ gameComponents: PropTypes.array.isRequired,
704
+ lobbyServer: PropTypes.string,
705
+ gameServer: PropTypes.string,
706
+ debug: PropTypes.bool,
707
+ clientFactory: PropTypes.func,
708
+ refreshInterval: PropTypes.number,
709
+ };
710
+ Lobby.defaultProps = {
711
+ debug: false,
712
+ clientFactory: Client,
713
+ refreshInterval: 2000,
714
+ };
715
+
716
+ export { Client, Lobby };