From aa77d0e90baf9be681b2df264cf5f4e0beec72a4 Mon Sep 17 00:00:00 2001 From: kcgidw Date: Sun, 19 Apr 2020 21:01:34 -0700 Subject: [PATCH] Allow players to rejoin an in-progress game --- src/public/js/faq-view.vue | 16 +++++---- src/public/js/state.js | 64 ++++++++++++++++++++---------------- src/server/schema.js | 3 -- src/server/socket-handler.js | 13 +++++++- 4 files changed, 57 insertions(+), 39 deletions(-) diff --git a/src/public/js/faq-view.vue b/src/public/js/faq-view.vue index 05d8c70..a50bca6 100644 --- a/src/public/js/faq-view.vue +++ b/src/public/js/faq-view.vue @@ -8,21 +8,23 @@
-

I found a bug!

-

- Bug reports are greatly appreciated! Contact me at - fakeartistonline@gmail.com, or post an issue on Github. -

- I accidentally quit my browser. Can I rejoin an in-progress game? + I accidentally quit my browser. How do I rejoin an in-progress game?

-

This is on the to-do list!

+

Join the room again with your username exactly as it was.

The website connection is spotty!

FAO's currently on Heroku's free hosting service.

(I would like to get a proper server and domain at some point!)

+
+

I found a bug!

+

+ Bug reports are greatly appreciated! Contact me at + fakeartistonline@gmail.com, or post an issue on Github. +

+

Will you implement ___?

diff --git a/src/public/js/state.js b/src/public/js/state.js index a74873c..3511145 100644 --- a/src/public/js/state.js +++ b/src/public/js/state.js @@ -26,7 +26,7 @@ const Store = { this.state.view = view; }, setGameState(newGameState) { - if(newGameState === undefined) { + if (newGameState === undefined) { this.state.gameState = undefined; this.setGameConnection(CONNECTION_STATE.DISCONNECT); this.setView(VIEW.HOME); @@ -34,14 +34,17 @@ const Store = { } this.setGameConnection(CONNECTION_STATE.CONNECT); - if(this.state.gameState === undefined) { + if (this.state.gameState === undefined) { this.state.gameState = generateClientGameState(); } this.state.gameState.adoptJson(newGameState); - if(this.state.gameState.phase === GAME_PHASE.SETUP) { + if (this.state.gameState.phase === GAME_PHASE.SETUP) { this.setView(VIEW.SETUP); - } else if(this.state.gameState.phase === GAME_PHASE.PLAY || this.state.gameState.phase === GAME_PHASE.VOTE) { + } else if ( + this.state.gameState.phase === GAME_PHASE.PLAY || + this.state.gameState.phase === GAME_PHASE.VOTE + ) { this.setView(VIEW.GAME); } }, @@ -49,9 +52,11 @@ const Store = { this.state.gameConnection = cs; }, myTurn() { - return this.state.gameState - && this.state.gameState.whoseTurn === this.state.username - && this.state.gameState.phase === GAME_PHASE.PLAY; + return ( + this.state.gameState && + this.state.gameState.whoseTurn === this.state.username && + this.state.gameState.phase === GAME_PHASE.PLAY + ); }, setWarning(warningName, message) { this.state[warningName] = message; @@ -67,22 +72,23 @@ const Store = { function handleSocket(messageName, handler, errHandler) { socket.on(messageName, function(data) { - if(data.err) { + if (data.err) { console.warn(data.err); - if(errHandler) { + if (errHandler) { errHandler(data.err); } return; } - if(handler) { + if (handler) { handler(data); } - if(data.roomState !== undefined) { + if (data.roomState !== undefined) { Store.setGameState(data.roomState); } }); } -handleSocket(MESSAGE.CREATE_ROOM, +handleSocket( + MESSAGE.CREATE_ROOM, function(data) { Store.setUsername(data.username); }, @@ -90,13 +96,14 @@ handleSocket(MESSAGE.CREATE_ROOM, Store.setWarning('createWarning', errMsg); } ); -handleSocket(MESSAGE.JOIN_ROOM, +handleSocket( + MESSAGE.JOIN_ROOM, function(data) { - if(data.username !== Store.state.username) { + if (data.username !== Store.state.username) { return; } Store.setWarning('joinWarning', undefined); - if(data.rejoin === true) { + if (data.rejoin === true) { console.log('Game reconnect success'); } }, @@ -113,10 +120,11 @@ handleSocket(MESSAGE.START_GAME); handleSocket(MESSAGE.NEW_TURN); handleSocket(MESSAGE.RETURN_TO_SETUP); -const usernameWarning = 'Username must be 1-20 characters long, and can only contain alphanumerics and spaces'; +const usernameWarning = + 'Username must be 1-20 characters long, and can only contain alphanumerics and spaces'; function submitCreateGame(username) { username = username.trim(); - if(validateUsername(username)) { + if (validateUsername(username)) { this.setWarning('createWarning', undefined); socket.emit(MESSAGE.CREATE_ROOM, { username: username, @@ -129,7 +137,7 @@ function submitCreateGame(username) { } function submitJoinGame(roomCode, username) { username = username.trim(); - if(validateUsername(username)) { + if (validateUsername(username)) { this.setWarning('joinWarning', undefined); socket.emit(MESSAGE.JOIN_ROOM, { roomCode: roomCode, @@ -162,8 +170,9 @@ function submitReturnToSetup() { socket.on('disconnect', function() { Store.state.gameConnection = CONNECTION_STATE.DISCONNECT; let existingGameState = Store.state.gameState; - if(existingGameState) { - switch(existingGameState.phase) { + if (existingGameState) { + let me = existingGameState.findUser(Store.state.username); + switch (existingGameState.phase) { case GAME_PHASE.SETUP: // if user was in room setup, just forget about the gamestate altogether // No need to handle reconnection, user should just join the room normally again @@ -171,8 +180,7 @@ socket.on('disconnect', function() { break; case GAME_PHASE.PLAY: case GAME_PHASE.VOTE: - let me = existingGameState.findUser(Store.state.username); - if(me) { + if (me) { me.connected = false; } break; @@ -187,13 +195,16 @@ socket.on('reconnect', reconnectToGame); function reconnectToGame() { let existingGameState = Store.state.gameState; let username = Store.state.username; - if(existingGameState && username && Store.state.gameConnection === CONNECTION_STATE.DISCONNECT) { + if ( + existingGameState && + username && + Store.state.gameConnection === CONNECTION_STATE.DISCONNECT + ) { Store.state.gameConnection = CONNECTION_STATE.RECONNECT; console.log('Attempting game rejoin.'); socket.emit(MESSAGE.JOIN_ROOM, { roomCode: existingGameState.roomCode, username: username, - rejoin: true, }); } } @@ -201,12 +212,9 @@ window.faodbg = { dcon() { socket.disconnect(); }, - recon() { - reconnectToGame(); - }, con() { socket.connect(); }, }; -export default Store; \ No newline at end of file +export default Store; diff --git a/src/server/schema.js b/src/server/schema.js index 705ccf8..ec985fc 100644 --- a/src/server/schema.js +++ b/src/server/schema.js @@ -35,9 +35,6 @@ SCHEMA[MESSAGE.JOIN_ROOM] = { type: ['string', 'number'], minLength: 1, }, - rejoin: { - type: 'boolean', - }, }, required: ['username', 'roomCode'], }; diff --git a/src/server/socket-handler.js b/src/server/socket-handler.js index 4895135..bbc9f6b 100644 --- a/src/server/socket-handler.js +++ b/src/server/socket-handler.js @@ -55,13 +55,16 @@ const MessageHandlers = { GamePrecond.roomExists(data.roomCode); let user; + const nameExistsInRoom = roomToJoin.findUser(data.username) !== undefined; - if (data.rejoin) { + if (nameExistsInRoom) { + // rejoin GamePrecond.nameIsTakenInRoom(data.username, roomToJoin); GamePrecond.gameInProgress(roomToJoin); user = login(sock, data.username, roomToJoin); joinRoom(user, roomToJoin, true, false); } else { + // join for first time GamePrecond.roomIsNotFull(roomToJoin); GamePrecond.gameNotInProgress(roomToJoin); GamePrecond.nameIsNotTakenInRoom(data.username, roomToJoin); @@ -259,6 +262,14 @@ const GamePrecond = { ); } }, + userIsDisconnected(username, room) { + if (!room.findUser(username).connected) { + throw new GameError( + `Username ${username} connected to ${room.roomCode}`, + 'This username is taken in this room' + ); + } + }, }; // send roomstate update to all users, accounting for different roles (i.e., faker vs artist)