@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,162 @@
1
+ /*
2
+ * Copyright 2018 The boardgame.io Authors
3
+ *
4
+ * Use of this source code is governed by a MIT-style
5
+ * license that can be found in the LICENSE file or at
6
+ * https://opensource.org/licenses/MIT.
7
+ */
8
+
9
+ import type { ComponentType } from 'react';
10
+ import { LobbyClient } from './client';
11
+ import type { Game, LobbyAPI } from '../types';
12
+
13
+ export interface GameComponent {
14
+ game: Game;
15
+ board: ComponentType<any>;
16
+ }
17
+
18
+ interface LobbyConnectionOpts {
19
+ server: string;
20
+ playerName?: string;
21
+ playerCredentials?: string;
22
+ gameComponents: GameComponent[];
23
+ }
24
+
25
+ class _LobbyConnectionImpl {
26
+ client: LobbyClient;
27
+ gameComponents: GameComponent[];
28
+ playerName: string;
29
+ playerCredentials?: string;
30
+ matches: LobbyAPI.MatchList['matches'];
31
+
32
+ constructor({
33
+ server,
34
+ gameComponents,
35
+ playerName,
36
+ playerCredentials,
37
+ }: LobbyConnectionOpts) {
38
+ this.client = new LobbyClient({ server });
39
+ this.gameComponents = gameComponents;
40
+ this.playerName = playerName || 'Visitor';
41
+ this.playerCredentials = playerCredentials;
42
+ this.matches = [];
43
+ }
44
+
45
+ async refresh() {
46
+ try {
47
+ this.matches = [];
48
+ const games = await this.client.listGames();
49
+ for (const game of games) {
50
+ if (!this._getGameComponents(game)) continue;
51
+ const { matches } = await this.client.listMatches(game);
52
+ this.matches.push(...matches);
53
+ }
54
+ } catch (error) {
55
+ throw new Error('failed to retrieve list of matches (' + error + ')');
56
+ }
57
+ }
58
+
59
+ _getMatchInstance(matchID: string) {
60
+ for (const inst of this.matches) {
61
+ if (inst['matchID'] === matchID) return inst;
62
+ }
63
+ }
64
+
65
+ _getGameComponents(gameName: string) {
66
+ for (const comp of this.gameComponents) {
67
+ if (comp.game.name === gameName) return comp;
68
+ }
69
+ }
70
+
71
+ _findPlayer(playerName: string) {
72
+ for (const inst of this.matches) {
73
+ if (inst.players.some((player) => player.name === playerName))
74
+ return inst;
75
+ }
76
+ }
77
+
78
+ async join(gameName: string, matchID: string, playerID: string) {
79
+ try {
80
+ let inst = this._findPlayer(this.playerName);
81
+ if (inst) {
82
+ throw new Error('player has already joined ' + inst.matchID);
83
+ }
84
+ inst = this._getMatchInstance(matchID);
85
+ if (!inst) {
86
+ throw new Error('game instance ' + matchID + ' not found');
87
+ }
88
+ const json = await this.client.joinMatch(gameName, matchID, {
89
+ playerID,
90
+ playerName: this.playerName,
91
+ });
92
+ inst.players[Number.parseInt(playerID)].name = this.playerName;
93
+ this.playerCredentials = json.playerCredentials;
94
+ } catch (error) {
95
+ throw new Error('failed to join match ' + matchID + ' (' + error + ')');
96
+ }
97
+ }
98
+
99
+ async leave(gameName: string, matchID: string) {
100
+ try {
101
+ const inst = this._getMatchInstance(matchID);
102
+ if (!inst) throw new Error('match instance not found');
103
+ for (const player of inst.players) {
104
+ if (player.name === this.playerName) {
105
+ await this.client.leaveMatch(gameName, matchID, {
106
+ playerID: player.id.toString(),
107
+ credentials: this.playerCredentials,
108
+ });
109
+ delete player.name;
110
+ delete this.playerCredentials;
111
+ return;
112
+ }
113
+ }
114
+ throw new Error('player not found in match');
115
+ } catch (error) {
116
+ throw new Error('failed to leave match ' + matchID + ' (' + error + ')');
117
+ }
118
+ }
119
+
120
+ async disconnect() {
121
+ const inst = this._findPlayer(this.playerName);
122
+ if (inst) {
123
+ await this.leave(inst.gameName, inst.matchID);
124
+ }
125
+ this.matches = [];
126
+ this.playerName = 'Visitor';
127
+ }
128
+
129
+ async create(gameName: string, numPlayers: number) {
130
+ try {
131
+ const comp = this._getGameComponents(gameName);
132
+ if (!comp) throw new Error('game not found');
133
+ if (
134
+ numPlayers < comp.game.minPlayers ||
135
+ numPlayers > comp.game.maxPlayers
136
+ )
137
+ throw new Error('invalid number of players ' + numPlayers);
138
+ await this.client.createMatch(gameName, { numPlayers });
139
+ } catch (error) {
140
+ throw new Error(
141
+ 'failed to create match for ' + gameName + ' (' + error + ')'
142
+ );
143
+ }
144
+ }
145
+ }
146
+
147
+ /**
148
+ * LobbyConnection
149
+ *
150
+ * Lobby model.
151
+ *
152
+ * @param {string} server - '<host>:<port>' of the server.
153
+ * @param {Array} gameComponents - A map of Board and Game objects for the supported games.
154
+ * @param {string} playerName - The name of the player.
155
+ * @param {string} playerCredentials - The credentials currently used by the player, if any.
156
+ *
157
+ * Returns:
158
+ * A JS object that synchronizes the list of running game instances with the server and provides an API to create/join/start instances.
159
+ */
160
+ export function LobbyConnection(opts: LobbyConnectionOpts) {
161
+ return new _LobbyConnectionImpl(opts);
162
+ }
@@ -0,0 +1,122 @@
1
+ /*
2
+ * Copyright 2018 The boardgame.io Authors.
3
+ *
4
+ * Use of this source code is governed by a MIT-style
5
+ * license that can be found in the LICENSE file or at
6
+ * https://opensource.org/licenses/MIT.
7
+ */
8
+
9
+ import React from 'react';
10
+ import type { Game } from '../types';
11
+ import type { GameComponent } from './connection';
12
+
13
+ type CreateMatchProps = {
14
+ games: GameComponent[];
15
+ createMatch: (gameName: string, numPlayers: number) => Promise<void>;
16
+ };
17
+
18
+ type CreateMatchState = {
19
+ selectedGame: number;
20
+ numPlayers: number;
21
+ };
22
+
23
+ class LobbyCreateMatchForm extends React.Component<
24
+ CreateMatchProps,
25
+ CreateMatchState
26
+ > {
27
+ state = {
28
+ selectedGame: 0,
29
+ numPlayers: 2,
30
+ };
31
+
32
+ constructor(props: CreateMatchProps) {
33
+ super(props);
34
+ /* fix min and max number of players */
35
+ for (const game of props.games) {
36
+ const matchDetails = game.game;
37
+ if (!matchDetails.minPlayers) {
38
+ matchDetails.minPlayers = 1;
39
+ }
40
+ if (!matchDetails.maxPlayers) {
41
+ matchDetails.maxPlayers = 4;
42
+ }
43
+ console.assert(matchDetails.maxPlayers >= matchDetails.minPlayers);
44
+ }
45
+ this.state = {
46
+ selectedGame: 0,
47
+ numPlayers: props.games[0].game.minPlayers,
48
+ };
49
+ }
50
+
51
+ _createGameNameOption = (game: GameComponent, idx: number) => {
52
+ return (
53
+ <option key={'name-option-' + idx} value={idx}>
54
+ {game.game.name}
55
+ </option>
56
+ );
57
+ };
58
+
59
+ _createNumPlayersOption = (idx: number) => {
60
+ return (
61
+ <option key={'num-option-' + idx} value={idx}>
62
+ {idx}
63
+ </option>
64
+ );
65
+ };
66
+
67
+ _createNumPlayersRange = (game: Game) => {
68
+ return Array.from({ length: game.maxPlayers + 1 })
69
+ .map((_, i) => i)
70
+ .slice(game.minPlayers);
71
+ };
72
+
73
+ render() {
74
+ return (
75
+ <div>
76
+ <select
77
+ value={this.state.selectedGame}
78
+ onChange={(evt) => this.onChangeSelectedGame(evt)}
79
+ >
80
+ {this.props.games.map((game, index) =>
81
+ this._createGameNameOption(game, index)
82
+ )}
83
+ </select>
84
+ <span>Players:</span>
85
+ <select
86
+ value={this.state.numPlayers}
87
+ onChange={this.onChangeNumPlayers}
88
+ >
89
+ {this._createNumPlayersRange(
90
+ this.props.games[this.state.selectedGame].game
91
+ ).map((number) => this._createNumPlayersOption(number))}
92
+ </select>
93
+ <span className="buttons">
94
+ <button onClick={this.onClickCreate}>Create</button>
95
+ </span>
96
+ </div>
97
+ );
98
+ }
99
+
100
+ onChangeNumPlayers = (event: React.ChangeEvent<HTMLSelectElement>) => {
101
+ this.setState({
102
+ numPlayers: Number.parseInt(event.target.value),
103
+ });
104
+ };
105
+
106
+ onChangeSelectedGame = (event: React.ChangeEvent<HTMLSelectElement>) => {
107
+ const idx = Number.parseInt(event.target.value);
108
+ this.setState({
109
+ selectedGame: idx,
110
+ numPlayers: this.props.games[idx].game.minPlayers,
111
+ });
112
+ };
113
+
114
+ onClickCreate = () => {
115
+ this.props.createMatch(
116
+ this.props.games[this.state.selectedGame].game.name,
117
+ this.state.numPlayers
118
+ );
119
+ };
120
+ }
121
+
122
+ export default LobbyCreateMatchForm;
@@ -0,0 +1,75 @@
1
+ /*
2
+ * Copyright 2018 The boardgame.io Authors.
3
+ *
4
+ * Use of this source code is governed by a MIT-style
5
+ * license that can be found in the LICENSE file or at
6
+ * https://opensource.org/licenses/MIT.
7
+ */
8
+
9
+ import React from 'react';
10
+
11
+ type LoginFormProps = {
12
+ playerName?: string;
13
+ onEnter: (playerName: string) => void;
14
+ };
15
+
16
+ type LoginFormState = {
17
+ playerName?: string;
18
+ nameErrorMsg: string;
19
+ };
20
+
21
+ class LobbyLoginForm extends React.Component<LoginFormProps, LoginFormState> {
22
+ static defaultProps = {
23
+ playerName: '',
24
+ };
25
+
26
+ state = {
27
+ playerName: this.props.playerName,
28
+ nameErrorMsg: '',
29
+ };
30
+
31
+ render() {
32
+ return (
33
+ <div>
34
+ <p className="phase-title">Choose a player name:</p>
35
+ <input
36
+ type="text"
37
+ value={this.state.playerName}
38
+ onChange={this.onChangePlayerName}
39
+ onKeyPress={this.onKeyPress}
40
+ />
41
+ <span className="buttons">
42
+ <button className="buttons" onClick={this.onClickEnter}>
43
+ Enter
44
+ </button>
45
+ </span>
46
+ <br />
47
+ <span className="error-msg">
48
+ {this.state.nameErrorMsg}
49
+ <br />
50
+ </span>
51
+ </div>
52
+ );
53
+ }
54
+
55
+ onClickEnter = () => {
56
+ if (this.state.playerName === '') return;
57
+ this.props.onEnter(this.state.playerName);
58
+ };
59
+
60
+ onKeyPress = (event: React.KeyboardEvent<HTMLInputElement>) => {
61
+ if (event.key === 'Enter') {
62
+ this.onClickEnter();
63
+ }
64
+ };
65
+
66
+ onChangePlayerName = (event: React.ChangeEvent<HTMLInputElement>) => {
67
+ const name = event.target.value.trim();
68
+ this.setState({
69
+ playerName: name,
70
+ nameErrorMsg: name.length > 0 ? '' : 'empty player name',
71
+ });
72
+ };
73
+ }
74
+
75
+ export default LobbyLoginForm;
@@ -0,0 +1,135 @@
1
+ /*
2
+ * Copyright 2018 The boardgame.io Authors.
3
+ *
4
+ * Use of this source code is governed by a MIT-style
5
+ * license that can be found in the LICENSE file or at
6
+ * https://opensource.org/licenses/MIT.
7
+ */
8
+
9
+ import React from 'react';
10
+ import type { LobbyAPI } from '../types';
11
+
12
+ export type MatchOpts = {
13
+ numPlayers: number;
14
+ matchID: string;
15
+ playerID?: string;
16
+ };
17
+
18
+ type Match = {
19
+ gameName: string;
20
+ matchID: string;
21
+ players: LobbyAPI.Match['players'];
22
+ };
23
+
24
+ type MatchInstanceProps = {
25
+ match: Match;
26
+ playerName: string;
27
+ onClickJoin: (gameName: string, matchID: string, playerID: string) => void;
28
+ onClickLeave: (gameName: string, matchID: string) => void;
29
+ onClickPlay: (gameName: string, matchOpts: MatchOpts) => void;
30
+ };
31
+
32
+ class LobbyMatchInstance extends React.Component<MatchInstanceProps> {
33
+ _createSeat = (player: { name?: string }) => {
34
+ return player.name || '[free]';
35
+ };
36
+
37
+ _createButtonJoin = (inst: Match, seatId: number) => (
38
+ <button
39
+ key={'button-join-' + inst.matchID}
40
+ onClick={() =>
41
+ this.props.onClickJoin(inst.gameName, inst.matchID, '' + seatId)
42
+ }
43
+ >
44
+ Join
45
+ </button>
46
+ );
47
+
48
+ _createButtonLeave = (inst: Match) => (
49
+ <button
50
+ key={'button-leave-' + inst.matchID}
51
+ onClick={() => this.props.onClickLeave(inst.gameName, inst.matchID)}
52
+ >
53
+ Leave
54
+ </button>
55
+ );
56
+
57
+ _createButtonPlay = (inst: Match, seatId: number) => (
58
+ <button
59
+ key={'button-play-' + inst.matchID}
60
+ onClick={() =>
61
+ this.props.onClickPlay(inst.gameName, {
62
+ matchID: inst.matchID,
63
+ playerID: '' + seatId,
64
+ numPlayers: inst.players.length,
65
+ })
66
+ }
67
+ >
68
+ Play
69
+ </button>
70
+ );
71
+
72
+ _createButtonSpectate = (inst: Match) => (
73
+ <button
74
+ key={'button-spectate-' + inst.matchID}
75
+ onClick={() =>
76
+ this.props.onClickPlay(inst.gameName, {
77
+ matchID: inst.matchID,
78
+ numPlayers: inst.players.length,
79
+ })
80
+ }
81
+ >
82
+ Spectate
83
+ </button>
84
+ );
85
+
86
+ _createInstanceButtons = (inst: Match) => {
87
+ const playerSeat = inst.players.find(
88
+ (player) => player.name === this.props.playerName
89
+ );
90
+ const freeSeat = inst.players.find((player) => !player.name);
91
+ if (playerSeat && freeSeat) {
92
+ // already seated: waiting for match to start
93
+ return this._createButtonLeave(inst);
94
+ }
95
+ if (freeSeat) {
96
+ // at least 1 seat is available
97
+ return this._createButtonJoin(inst, freeSeat.id);
98
+ }
99
+ // match is full
100
+ if (playerSeat) {
101
+ return (
102
+ <div>
103
+ {[
104
+ this._createButtonPlay(inst, playerSeat.id),
105
+ this._createButtonLeave(inst),
106
+ ]}
107
+ </div>
108
+ );
109
+ }
110
+ // allow spectating
111
+ return this._createButtonSpectate(inst);
112
+ };
113
+
114
+ render() {
115
+ const match = this.props.match;
116
+ let status = 'OPEN';
117
+ if (!match.players.some((player) => !player.name)) {
118
+ status = 'RUNNING';
119
+ }
120
+ return (
121
+ <tr key={'line-' + match.matchID}>
122
+ <td key={'cell-name-' + match.matchID}>{match.gameName}</td>
123
+ <td key={'cell-status-' + match.matchID}>{status}</td>
124
+ <td key={'cell-seats-' + match.matchID}>
125
+ {match.players.map((player) => this._createSeat(player)).join(', ')}
126
+ </td>
127
+ <td key={'cell-buttons-' + match.matchID}>
128
+ {this._createInstanceButtons(match)}
129
+ </td>
130
+ </tr>
131
+ );
132
+ }
133
+ }
134
+
135
+ export default LobbyMatchInstance;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @jest-environment node
3
+ */
4
+
5
+ import React from 'react';
6
+ import Lobby from './react';
7
+ import ReactDOMServer from 'react-dom/server';
8
+
9
+ /* mock server requests */
10
+ global.fetch = jest
11
+ .fn()
12
+ .mockReturnValue({ ok: true, status: 200, json: () => [] });
13
+
14
+ describe('lobby', () => {
15
+ test('is rendered', () => {
16
+ const components: any[] = [{ board: 'Board', game: { name: 'GameName' } }];
17
+ const ssrRender = ReactDOMServer.renderToString(
18
+ <Lobby gameServer="localhost" gameComponents={components} />
19
+ );
20
+ expect(ssrRender).toContain('lobby-view');
21
+ });
22
+ });