-
Notifications
You must be signed in to change notification settings - Fork 716
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
fb9b41e
commit a32d3d5
Showing
16 changed files
with
1,669 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
/* | ||
* Copyright 2018 The boardgame.io Authors. | ||
* | ||
* Use of this source code is governed by a MIT-style | ||
* license that can be found in the LICENSE file or at | ||
* https://opensource.org/licenses/MIT. | ||
*/ | ||
|
||
import routes from './routes'; | ||
|
||
// Any other additional setup for this module | ||
export default { | ||
routes, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
/* | ||
* Copyright 2018 The boardgame.io Authors. | ||
* | ||
* Use of this source code is governed by a MIT-style | ||
* license that can be found in the LICENSE file or at | ||
* https://opensource.org/licenses/MIT. | ||
*/ | ||
|
||
#lobby-view { | ||
display: flex; | ||
flex-direction: column; | ||
width: 100%; | ||
} | ||
|
||
.phase-title { | ||
margin-top: 40px; | ||
} | ||
|
||
.hidden { | ||
display: none; | ||
} | ||
|
||
.phase { | ||
border: none; | ||
outline: none; | ||
} | ||
|
||
#game-creation select { | ||
font-size: 14px; | ||
margin-right: 10px; | ||
} | ||
|
||
#game-creation span { | ||
margin-right: 10px; | ||
} | ||
|
||
#instances td { | ||
list-style: none; | ||
border: 0px solid #eee; | ||
border-top: none; | ||
height: 30px; | ||
line-height: 30px; | ||
text-align: left; | ||
font-size: 14px; | ||
padding-left: 10px; | ||
padding-right: 10px; | ||
} | ||
|
||
#instances table { | ||
height: 100%; | ||
width: 500px; | ||
white-space: nowrap; | ||
} | ||
|
||
#instances button { | ||
font-size: 12px; | ||
} | ||
|
||
.error-msg { | ||
font-size: 12px; | ||
color: red; | ||
margin-top: 10px; | ||
margin-bottom: 10px; | ||
display: block; | ||
} | ||
|
||
.buttons button { | ||
margin-left: 10px; | ||
margin-top: 10px; | ||
width: 70px; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
/* | ||
* Copyright 2018 The boardgame.io Authors. | ||
* | ||
* Use of this source code is governed by a MIT-style | ||
* license that can be found in the LICENSE file or at | ||
* https://opensource.org/licenses/MIT. | ||
*/ | ||
|
||
import React from 'react'; | ||
import { Lobby } from 'boardgame.io/react'; | ||
import { default as BoardTicTacToe } from '../tic-tac-toe/board'; | ||
import { default as BoardChess } from '../chess/board'; | ||
import { default as GameTicTacToe } from '../tic-tac-toe/game'; | ||
import { default as GameChess } from '../chess/game'; | ||
import './lobby.css'; | ||
|
||
GameTicTacToe.minPlayers = 1; | ||
GameTicTacToe.maxPlayers = 2; | ||
GameChess.minPlayers = GameChess.maxPlayers = 2; | ||
|
||
const importedGames = [ | ||
{ game: GameTicTacToe, board: BoardTicTacToe }, | ||
{ game: GameChess, board: BoardChess }, | ||
]; | ||
|
||
const LobbyView = () => ( | ||
<div style={{ padding: 50 }}> | ||
<h1>Lobby</h1> | ||
|
||
<Lobby | ||
gameServer="localhost:8000" | ||
lobbyServer="localhost:8001" | ||
gameComponents={importedGames} | ||
/> | ||
</div> | ||
); | ||
|
||
export default LobbyView; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
/* | ||
* Copyright 2018 The boardgame.io Authors. | ||
* | ||
* Use of this source code is governed by a MIT-style | ||
* license that can be found in the LICENSE file or at | ||
* https://opensource.org/licenses/MIT. | ||
*/ | ||
|
||
import LobbyView from './lobby'; | ||
|
||
const routes = [ | ||
{ | ||
path: '/lobby/main', | ||
text: 'Example', | ||
component: LobbyView, | ||
}, | ||
]; | ||
|
||
export default routes; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
/* | ||
* Copyright 2018 The boardgame.io Authors | ||
* | ||
* Use of this source code is governed by a MIT-style | ||
* license that can be found in the LICENSE file or at | ||
* https://opensource.org/licenses/MIT. | ||
*/ | ||
|
||
class _LobbyConnectionImpl { | ||
constructor({ server, gameComponents, playerName, playerCredentials }) { | ||
this.gameComponents = gameComponents; | ||
this.playerName = playerName || 'Visitor'; | ||
this.playerCredentials = playerCredentials; | ||
this.server = server; | ||
this.gameInstances = []; | ||
} | ||
|
||
_baseUrl() { | ||
if (this.server) { | ||
return `http://${this.server}/games`; | ||
} | ||
return '/games'; | ||
} | ||
|
||
async refresh() { | ||
try { | ||
this.gameInstances.length = 0; | ||
const resp = await fetch(this._baseUrl()); | ||
if (resp.status !== 200) { | ||
throw 'HTTP status ' + resp.status; | ||
} | ||
const json = await resp.json(); | ||
for (let gameName of json) { | ||
if (!this._getGameComponents(gameName)) continue; | ||
const gameResp = await fetch(this._baseUrl() + '/' + gameName); | ||
const gameJson = await gameResp.json(); | ||
for (let inst of gameJson.gameInstances) { | ||
inst.gameName = gameName; | ||
} | ||
this.gameInstances = this.gameInstances.concat(gameJson.gameInstances); | ||
} | ||
} catch (error) { | ||
throw new Error('failed to retrieve list of games (' + error + ')'); | ||
} | ||
} | ||
|
||
_getGameInstance(gameID) { | ||
for (let inst of this.gameInstances) { | ||
if (inst['gameID'] === gameID) return inst; | ||
} | ||
} | ||
|
||
_getGameComponents(gameName) { | ||
for (let comp of this.gameComponents) { | ||
if (comp.game.name == gameName) return comp; | ||
} | ||
} | ||
|
||
_findPlayer(playerName) { | ||
for (let inst of this.gameInstances) { | ||
if (inst.players.some(player => player.name === playerName)) return inst; | ||
} | ||
} | ||
|
||
async join(gameName, gameID, playerID) { | ||
try { | ||
let inst = this._findPlayer(this.playerName); | ||
if (inst) { | ||
throw 'player has already joined ' + inst.gameID; | ||
} | ||
inst = this._getGameInstance(gameID); | ||
if (!inst) { | ||
throw 'game instance ' + gameID + ' not found'; | ||
} | ||
const resp = await fetch( | ||
this._baseUrl() + '/' + gameName + '/' + gameID + '/join', | ||
{ | ||
method: 'POST', | ||
body: JSON.stringify({ | ||
playerID: playerID, | ||
playerName: this.playerName, | ||
}), | ||
headers: { 'Content-Type': 'application/json' }, | ||
} | ||
); | ||
if (resp.status !== 200) throw 'HTTP status ' + resp.status; | ||
const json = await resp.json(); | ||
inst.players[Number.parseInt(playerID)].name = this.playerName; | ||
this.playerCredentials = json.playerCredentials; | ||
} catch (error) { | ||
throw new Error('failed to join room ' + gameID + ' (' + error + ')'); | ||
} | ||
} | ||
|
||
async leave(gameName, gameID) { | ||
try { | ||
let inst = this._getGameInstance(gameID); | ||
if (!inst) throw 'game instance not found'; | ||
for (let player of inst.players) { | ||
if (player.name === this.playerName) { | ||
const resp = await fetch( | ||
this._baseUrl() + '/' + gameName + '/' + gameID + '/leave', | ||
{ | ||
method: 'POST', | ||
body: JSON.stringify({ | ||
playerID: player.id, | ||
playerCredentials: this.playerCredentials, | ||
}), | ||
headers: { 'Content-Type': 'application/json' }, | ||
} | ||
); | ||
if (resp.status !== 200) throw 'HTTP status ' + resp.status; | ||
delete player.name; | ||
delete this.playerCredentials; | ||
return; | ||
} | ||
} | ||
throw 'player not found in room'; | ||
} catch (error) { | ||
throw new Error('failed to leave room ' + gameID + ' (' + error + ')'); | ||
} | ||
} | ||
|
||
async disconnect() { | ||
let inst = this._findPlayer(this.playerName); | ||
if (inst) { | ||
await this.leave(inst.gameName, inst.gameID); | ||
} | ||
this.gameInstances = []; | ||
this.playerName = 'Visitor'; | ||
} | ||
|
||
async create(gameName, numPlayers) { | ||
try { | ||
const comp = this._getGameComponents(gameName); | ||
if (!comp) throw 'game not found'; | ||
if ( | ||
numPlayers < comp.game.minPlayers || | ||
numPlayers > comp.game.maxPlayers | ||
) | ||
throw 'invalid number of players ' + numPlayers; | ||
const resp = await fetch(this._baseUrl() + '/' + gameName + '/create', { | ||
method: 'POST', | ||
body: JSON.stringify({ | ||
numPlayers: numPlayers, | ||
}), | ||
headers: { 'Content-Type': 'application/json' }, | ||
}); | ||
if (resp.status !== 200) throw 'HTTP status ' + resp.status; | ||
} catch (error) { | ||
throw new Error( | ||
'failed to create room for ' + gameName + ' (' + error + ')' | ||
); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* LobbyConnection | ||
* | ||
* Lobby model. | ||
* | ||
* @param {string} server - '<host>:<port>' of the server. | ||
* @param {Array} gameComponents - A map of Board and Game objects for the supported games. | ||
* @param {string} playerName - The name of the player. | ||
* @param {string} playerCredentials - The credentials currently used by the player, if any. | ||
* | ||
* Returns: | ||
* A JS object that synchronizes the list of running game instances with the server and provides an API to create/join/start instances. | ||
*/ | ||
export function LobbyConnection(opts) { | ||
return new _LobbyConnectionImpl(opts); | ||
} |
Oops, something went wrong.