commit d64704812a643d70126792c2e04a2197d78a2d76 (patch)
parent 1003ff9a3c3db67c83f20a427572018b5046b21b
Author: Chris Karle <chriskarle@hotmail.com>
Date: Sun, 26 Apr 2020 18:11:28 -0400
app, CardTable, Lobby: implement rejoin logic
Add extra processing and state necessary to allow any
active client to be replaced by playerName+tableName with
a new connection. Tested in basic lobby, vote and play
phases.
Diffstat:
3 files changed, 152 insertions(+), 25 deletions(-)
diff --git a/assets/app.js b/assets/app.js
@@ -22,11 +22,14 @@ class App extends React.Component {
this.state = {
playerName: initialName,
tableName: initialTable,
- showTable: tableDebug
+ showTable: false,
+ uniqueError: false,
+ firstMsg: null
};
const host = window.location.host;
const clientAddr = 'ws://' + host + '/play';
client = new W3CWebSocket(clientAddr);
+ client.onmessage = (event) => this.processResponse(event);
if (tableDebug) {
// on tableDebug send join plus add 3 fakeClient players that join+sit
fc1 = new W3CWebSocket(clientAddr);
@@ -46,20 +49,77 @@ class App extends React.Component {
);
}
+ // need to only showTable if no user-not-unique
+ // only process incoming if we're waiting to join table
+ // on joinTable success get first 'lobby' phase, put msg on
+ // CardTable.firstMsg prop for table init
+ processResponse = event => {
+ const {showTable} = this.state;
+ if (!showTable){
+ let msg = JSON.parse(event.data);
+ if (msg) {
+ if ('pong' != msg.msg_type){
+ // console.log('App procResp');
+ if (msg.msg_type == 'game_state'){
+ //replace w switch if more than one needed
+ // if (msg.game && msg.game.phase == 'lobby'){
+ //set firstMsg, then set showTable
+ // console.log('App.procResp: set firstMsg & showTable');
+ this.setState({
+ firstMsg: msg
+ }, () => {
+ this.setState({
+ showTable: true
+ })
+ });
+ // };
+ } else if (msg.msg_type == 'error'){
+ if (msg.msg && msg.msg.includes('Username not unique')){
+ // show confirm-force
+ // console.log('NOT UNIQUE!!');
+ this.setState({
+ uniqueError: true
+ });
+ }
+ }
+ }
+ }
+ }
+ }
+
chooseTable = tableName => {
- const show = tableName && tableName != '';
+ if (!tableName || tableName == ''){
+ client.onmessage = (event) => this.processResponse(event);
+ this.setState({
+ firstMsg: null
+ });
+ };
this.setState( {
tableName: tableName,
- showTable: show
+ showTable: false
}, () => {
- client.send(JSON.stringify({
- action:'join_game',
- player_name: this.state.playerName,
- game_id: tableName
- }));
+ if (tableName && tableName != ''){
+ client.send(JSON.stringify({
+ action:'join_game',
+ player_name: this.state.playerName,
+ game_id: tableName
+ }));
+ }
});
}
+ forceJoin = () => {
+ // console.log('send force rejoin');
+ // should only be calling this on unique error and user wants force rejoin
+ // so all other state should be correct
+ client.send(JSON.stringify({
+ action:'join_game',
+ player_name: this.state.playerName,
+ game_id: this.state.tableName,
+ force: true
+ }));
+ }
+
setFakeGame = (initialName, initialTable) => {
client.send(JSON.stringify({ action:'join_game', player_name: initialName, game_id: initialTable }));
fc1.send(JSON.stringify({ action:'join_game', player_name: 'Betty', game_id: initialTable }));
@@ -71,7 +131,7 @@ class App extends React.Component {
}
render () {
- const {showTable, playerName, tableName} = this.state;
+ const {showTable, playerName, tableName, firstMsg, uniqueError} = this.state;
return (
<div id="top-app">
{!showTable && (
@@ -79,6 +139,8 @@ class App extends React.Component {
setName={this.setPlayerName}
chooseTable={this.chooseTable}
name={playerName}
+ uniqueError={uniqueError}
+ forceJoin={this.forceJoin}
/>
)}
{showTable && (
@@ -86,7 +148,7 @@ class App extends React.Component {
chooseTable={this.chooseTable}
name={playerName}
tableName={tableName}
- active={showTable}
+ firstMsg={firstMsg}
client={client}
/>
)}
diff --git a/assets/components/CardTable.js b/assets/components/CardTable.js
@@ -54,14 +54,24 @@ export default class CardTable extends React.Component {
};
componentDidMount () {
- const {name, tableName, client} = this.props;
+ const {name, tableName, client, firstMsg} = this.props;
client.onmessage = (event) => this.processResponse(event);
const welcomeMsg = 'Welcome to the ' + tableName + ' table, ' + name + '!';
+ if (firstMsg) {
+ this.processFirstMessage(firstMsg);
+ }
this.setState({
bannerMsg: welcomeMsg
});
};
+ componentDidUpdate (prevProps) {
+ const {firstMsg} = this.props;
+ if (firstMsg && !prevProps.firstMsg) {
+ this.processFirstMessage(firstMsg);
+ }
+ }
+
processResponse = (event) => {
let msg = JSON.parse(event.data);
if ('pong' != msg.msg_type) {
@@ -95,17 +105,62 @@ export default class CardTable extends React.Component {
};
};
+ processFirstMessage = msg => {
+ // console.log('processFirstMessage');
+ // in cases of forceRejoin, the firstMsg could be lobby, vote, play
+ // for cases of ordinary game join, will be lobby
+ if (msg && msg.game) {
+ switch (msg.game.phase) {
+ case 'lobby':
+ this.processLobby(msg);
+ break;
+ case 'vote':
+ this.processFirstMsgVote(msg);
+ break;
+ case 'play':
+ this.processFirstMsgPlay(msg);
+ break;
+ }
+ }
+ }
+
+ processFirstMsgPlay = msg => {
+ this.initMySeat(msg);
+ setTimeout(this.gameStartSetup, 300, msg);
+ setTimeout(this.handStartSetup, 600, msg);
+ setTimeout(this.processPlay, 900, msg);
+ // this.gameStartSetup(msg);
+ // this.handStartSetup(msg);
+ // this.processPlay(msg);
+ }
+
+ processFirstMsgVote = msg => {
+ this.initMySeat(msg);
+ setTimeout(this.gameStartSetup, 300, msg);
+ setTimeout(this.processVote, 600, msg);
+ // this.gameStartSetup(msg);
+ // this.processVote(msg);
+ }
+
+ // OK to let processLobby run twice on first lobby msg, which
+ // may happen if CardTable already mounted on join_table
processLobby = (msg) => {
+ this.initMySeat(msg);
+ this.setState({
+ phase: 'lobby'
+ });
+ };
+
+ initMySeat = msg => {
if (msg.game.players) {
const plAr = msg.game.players;
const mySeat = plAr.findIndex( x => x == this.props.name );
this.setState({
playerNames: plAr,
mySeat: mySeat,
- phase: 'lobby'
- })
+ });
};
- };
+ }
processVote = (msg) => {
if (this.state.phase == 'lobby') {
@@ -183,9 +238,6 @@ export default class CardTable extends React.Component {
}
processPause = msg => {
- // console.log('new t:', msg.game.tricks);
- // console.log('old t:', this.state.tricks);
- // console.log('start processPause, msg.hand=', msg.hand);
let trickWinIndex = -1;
let trickWinner = '';
for (let i = 0; i < 4; i++){
@@ -198,7 +250,6 @@ export default class CardTable extends React.Component {
//must be?? sanity check
trickWinner = this.state.playerNames[trickWinIndex] + ' takes the trick!'
}
- // console.log('trickWinIndex = ', trickWinIndex);
this.setState ({
table: msg.game.table,
handLengths: msg.game.hand_lengths,
@@ -301,7 +352,6 @@ export default class CardTable extends React.Component {
let tpIndex = msg.game.dealer - mySeat;
tpIndex = (tpIndex < 0) ? tpIndex + 4 : tpIndex;
const trumpPlace = trumpPlacement[tpIndex];
- console.log('trumpPlace:', trumpPlace);
this.setState ({
leftName: playerNames[leftSeat],
leftSeat: leftSeat,
@@ -342,18 +392,18 @@ export default class CardTable extends React.Component {
this.props.client.send(JSON.stringify({
action: 'start_game', start_seat: startDealer
}));
- console.log('start game, dealer = ', startDealer);
+ // console.log('start game, dealer = ', startDealer);
};
sendVote = (voteObject) => {
const voteString = JSON.stringify(voteObject);
- console.log('sendVote:', voteString);
+ // console.log('sendVote:', voteString);
this.props.client.send(voteString);
};
sendCard = (index) => {
const {phase, myCards} = this.state;
- console.log('card click ', myCards[index]);
+ // console.log('card click ', myCards[index]);
if (phase == 'swap') {
this.props.client.send(JSON.stringify({
action:'dealer_swap', card: myCards[index]
@@ -569,6 +619,6 @@ CardTable.propTypes = {
chooseTable: PropTypes.func,
name: PropTypes.string,
tableName: PropTypes.string,
- active: PropTypes.bool,
+ firstMsg: PropTypes.object,
client: PropTypes.object
}
\ No newline at end of file
diff --git a/assets/components/Lobby.js b/assets/components/Lobby.js
@@ -52,7 +52,7 @@ export default class Lobby extends React.Component {
}
render () {
- const {name} = this.props;
+ const {name, uniqueError} = this.props;
const {nameIn, nameError, tableIn, tableError} = this.state;
return (
<div id="lobby" className="lobby__outer">
@@ -110,6 +110,19 @@ export default class Lobby extends React.Component {
</div>
</div>
)}
+ {uniqueError && (
+ <div>
+ <h3>Hmm, a player named {name} is at the table...</h3>
+ <p>You need a unique player name, which you can change in the top input above.</p>
+ <p><emphasis>OR </emphasis> if you lost your connection and want to re-join the
+ game as player "{name}" from this page, press the REJOIN button below</p>
+ <Button
+ className="rejoin__button"
+ kind="primary"
+ onClick={()=>this.props.forceJoin()}
+ >REJOIN</Button>
+ </div>
+ )}
</div>
);
};
@@ -118,5 +131,7 @@ export default class Lobby extends React.Component {
Lobby.propTypes = {
setName: PropTypes.func,
chooseTable: PropTypes.func,
- name: PropTypes.string
+ name: PropTypes.string,
+ uniqueError: PropTypes.bool,
+ forceJoin: PropTypes.func
}
\ No newline at end of file