From 09cecf762df31fa3e5b4250e2e1d2c49fefc9c69 Mon Sep 17 00:00:00 2001 From: Benjamin Kyd Date: Wed, 17 Mar 2021 01:33:40 +0000 Subject: [PATCH] Lobbiesss! lot of networking to do tho --- TODO | 2 +- client/public/game/lobbies.js | 20 +++++---- server/src/game-registrar.js | 4 +- server/src/lobbies.js | 85 ++++++++++++++++++++++++++++++----- server/src/router.js | 2 - server/src/socketserver.js | 83 +++++++++++++++++++++++++++++++--- 6 files changed, 164 insertions(+), 32 deletions(-) diff --git a/TODO b/TODO index 715c96e..f07eca1 100644 --- a/TODO +++ b/TODO @@ -6,7 +6,7 @@ [x] User sockets, or "users" are made innactive after timeout on socket - Prevents softlock of users and stops socket spamming [-] Game lobying system - [ ] Delete lobby once user disconnects + [ ] Delete lobby once user disconnects - no reconnection [ ] Matchmaking system [ ] 1v1 game framework that allows spectators [ ] diff --git a/client/public/game/lobbies.js b/client/public/game/lobbies.js index 06ecc66..13d12bb 100644 --- a/client/public/game/lobbies.js +++ b/client/public/game/lobbies.js @@ -84,6 +84,7 @@ function createLobby() } socket.on('lobby-create-success', lobby => { + document.querySelector('#lobby-success').innerHTML = ""; const successDiv = document.createElement('div'); successDiv.id = 'lobby-success'; successDiv.innerHTML = 'SUCCESS: Lobby created, Joining...'; @@ -91,6 +92,7 @@ socket.on('lobby-create-success', lobby => { }); socket.on('lobby-create-error', (...args) => { + document.querySelector('#lobby-error').innerHTML = ""; const errorDiv = document.createElement('div'); errorDiv.id = 'lobby-error'; errorDiv.innerHTML = 'ERROR: An error occured while creating the lobby' + JSON.stringify(args); @@ -141,30 +143,35 @@ function joinLobby() socket.on('lobby-join-success', (lobby) => { showActive(); const lobbyDiv = document.createElement('div'); + ActiveLobbyBlock.innerHTML = ""; lobbyDiv.id = lobby.id; // TODO: Make drawlobby function lobbyDiv.innerHTML += `

Lobby ${lobby.name}

Join Code: ${lobby.uid}

Players:`; for (const player of lobby.players) - lobbyDiv.innerHTML += player.name + ' '; + lobbyDiv.innerHTML += `${player.name}, ` + // remove trailing comma + lobbyDiv.innerHTML = lobbyDiv.innerHTML.slice(0, -2); if (lobby.allowspectators) { lobbyDiv.innerHTML += '

Spectators:'; for (const player of lobby.spectators) - lobbyDiv.innerHTML += player.name + ' '; + lobbyDiv.innerHTML += `${player.name}, ` + lobbyDiv.innerHTML = lobbyDiv.innerHTML.slice(0, -2); } lobbyDiv.innerHTML += `

Visibility: ${lobby.visibility}

State: ${lobby.state}` lobbyDiv.innerHTML += '' - lobbyDiv.innerHTML += '' + lobbyDiv.innerHTML += '' ActiveLobbyBlock.appendChild(lobbyDiv); }); socket.on('lobby-join-error', (...args) => { + document.querySelector('#lobby-error').innerHTML = ""; const errorDiv = document.createElement('div'); errorDiv.id = 'lobby-error'; errorDiv.innerHTML = 'ERROR: An error occured while joining the lobby' + JSON.stringify(args); @@ -178,12 +185,9 @@ socket.on('lobby-update'); function leaveLobby() { - // TODO: if in lobby AND owner of lobby - socket.emit('lobby-destroy'); - - // TODO: if in lobby + // TODO: error check socket.emit('lobby-leave'); - + showBack(); } function destructLobbies() diff --git a/server/src/game-registrar.js b/server/src/game-registrar.js index c5a7365..c051090 100644 --- a/server/src/game-registrar.js +++ b/server/src/game-registrar.js @@ -103,7 +103,7 @@ function RegisterUser(username, ip) connectionid: 'none', }; - Logger.info(`${uid} REGISTERING WITH ${ip} AS ${username}`); + Logger.info(`USER ${uid} (${username}) REGISTERING WITH ${ip} AS ${username}`); return OnlineUsers[uid]; } @@ -138,7 +138,7 @@ function UserConnect(useruid, connectionid) OnlineUsers[useruid].connectionid = connectionid; OnlineUsers[useruid].state = 'CONNECTED'; - Logger.info(`SOCKET ${connectionid} IDENTIFIED AS ${useruid} (${OnlineUsers[useruid].username})`); + Logger.game(`SOCKET ${connectionid} IDENTIFIED AS ${useruid} (${OnlineUsers[useruid].username})`); return true; } diff --git a/server/src/lobbies.js b/server/src/lobbies.js index c1f3682..631670d 100644 --- a/server/src/lobbies.js +++ b/server/src/lobbies.js @@ -17,7 +17,7 @@ LOBBY OBJECT } NOTES - Users can only own one lobby - - Lobby UID is "join code", will be much shorter than userid + - Lobby UID is "join code", will be much shorter than useruid - When inactive will be deleted, unlike users - It's a waste of memory to store the name along with the useruid, however i believe it will save complexity in the domain logic @@ -32,9 +32,11 @@ function CheckUserAvailability(useruid) // if user owns lobby if (Lobbies[lobby].owneruid === useruid) return false; // if user is in any lobbies already - if (Lobbies[lobby].players.includes(useruid)) return false; + for (const player of Lobbies[lobby].players) + if (player.uid === useruid) return false; // if user is spectating any lobbies already - if (Lobbies[lobby].spectators.includes(useruid)) return false; + for (const player of Lobbies[lobby].spectators) + if (player.uid === useruid) return false; } return true; @@ -42,21 +44,27 @@ function CheckUserAvailability(useruid) function IsUserInLobby(useruid) { + // Doesn't matter if they own the lobby, if they do, they're + // included in the player list + // TODO: potential bug, if user has created but not joined their lobby for (const lobby in Lobbies) { // if user is in any lobbies already - if (Lobbies[lobby].players.includes(useruid)) return true; + for (const player of Lobbies[lobby].players) + if (player.uid === useruid) return true; // if user is spectating any lobbies already - if (Lobbies[lobby].spectators.includes(useruid)) return true; + for (const player of Lobbies[lobby].spectators) + if (player.uid === useruid) return true; } return false; } -function DoesUserOwnLobby(lobbyuid, useruid) +function DoesUserOwnLobby(useruid) { - if (!Lobbies[lobbyuid]) return false; - if (Lobbies[lobbyuid].owneruid === useruid) return true; + for (const lobby in Lobbies) + if (Lobbies[lobby].owneruid === useruid) return true; + return false; } @@ -66,13 +74,32 @@ function GetLobbyByUID(lobbyuid) return Lobbies[lobbyuid]; } -function GetLobbyByUserUID(owneruid) +function GetLobbyByOwnerUID(owneruid) { for (const lobby in Lobbies) - if (Lobbies[lobby].owneruid == owneruid) return Lobbies[lobby]; + if (Lobbies[lobby].owneruid === owneruid) return Lobbies[lobby]; return false; } +function GetLobbyByUserUID(playeruid) +{ + for (const lobby in Lobbies) + { + for (const player of Lobbies[lobby].players) + if (player.uid === playeruid) return Lobbies[lobby]; + for (const player of Lobbies[lobby].spectators) + if (player.uid === playeruid) return Lobbies[lobby]; + } + + + return false; +} + +function GetPublicLobbies() +{ + +} + function RegisterLobby(owneruid, name, private, spectators) { @@ -94,13 +121,14 @@ function RegisterLobby(owneruid, name, private, spectators) state: 'OPEN' }; + Logger.game(`LOBBY ${uid} REGISTERED BY USER ${owneruid} (${Registrar.GetUserByUID(owneruid).username})`); return Lobbies[uid]; - } function DeRegisterLobby(lobbyuid) { delete Lobbies[lobbyuid]; + Logger.game(`LOBBY ${lobbyuid} DEREGISTERED`); } function UserJoinLobby(lobbyuid, useruid) @@ -109,11 +137,40 @@ function UserJoinLobby(lobbyuid, useruid) if (!Lobbies[lobbyuid]) return false; if (!Registrar.GetUserByUID(useruid)) return false; - Lobbies[lobbyuid].players.push({uid: useruid, name: Registrar.GetUserByUID(useruid).username}); + // check users and change lobby status + + const user = Registrar.GetUserByUID(useruid); + Lobbies[lobbyuid].players.push({uid: useruid, name: user.username}); + + Logger.game(`LOBBY ${lobbyuid} USER ${useruid} (${user.username}) JOINING`); return GetLobbyByUID(lobbyuid); } +// works for spectators too +function UserLeaveLobby(useruid) +{ + if (!IsUserInLobby(useruid)) return false; + + // If user owns lobby, delete it + if (DoesUserOwnLobby(useruid)) + { + const lobby = GetLobbyByOwnerUID(useruid); + Logger.game(`LOBBY ${lobby.uid} OWNER ${useruid} (${Registrar.GetUserByUID(useruid).username}) LEAVING`); + DeRegisterLobby(lobby.uid); + return true; + } + + const lobby = GetLobbyByUserUID(useruid); + + console.log(Lobbies[lobby.uid]); + delete Lobbies[lobby.uid].players[useruid]; + delete Lobbies[lobby.uid].spectators[useruid]; + console.log(Lobbies[lobby.uid]); + + return true; +} + function SpectatorJoinLobby(lobbyuid, useruid) { @@ -128,11 +185,15 @@ module.exports = { // Get lobby exports GetLobbyByUID: GetLobbyByUID, + GetLobbyByOwnerUID: GetLobbyByOwnerUID, GetLobbyByUserUID: GetLobbyByUserUID, + GetPublicLobbies: GetPublicLobbies, // Change lobby state exports + // TODO: take callback for update client event RegisterLobby: RegisterLobby, DeRegisterLobby: DeRegisterLobby, UserJoinLobby: UserJoinLobby, + UserLeaveLobby: UserLeaveLobby, SpectatorJoinLobby: SpectatorJoinLobby } diff --git a/server/src/router.js b/server/src/router.js index c9afbe7..83761f4 100644 --- a/server/src/router.js +++ b/server/src/router.js @@ -99,8 +99,6 @@ function HandleLogin(req, res, next) } } - Logger.info(`NEW USER ID ${user.uid}`); - res.end(JSON.stringify(response)); // Continue to later middleware diff --git a/server/src/socketserver.js b/server/src/socketserver.js index 738113e..2747548 100644 --- a/server/src/socketserver.js +++ b/server/src/socketserver.js @@ -50,10 +50,8 @@ async function Router(socket) socket.on('identify', args => ClientIdentify(socket, args)); socket.on('lobby-create', args => LobbyCreate(socket, args)); - // socket.on('lobby-destroy'); - socket.on('lobby-join', args => LobbyJoin(socket, args)); - // socket.on('lobby-leave'); + socket.on('lobby-leave', args => LobbyLeave(socket, args)); socket.on('disconnect', args => HandleDisconnect(socket, ...args)); @@ -117,7 +115,7 @@ function LobbyCreate(socket, args) return; } - if (!args.lobbyName || args.lobbyPrivate === undefined || args.lobbySpectators === undefined) + if (!args.lobbyName || args.lobbyPrivate === undefined || args.lobbySpectators === undefined) { err.addError(400, 'Bad Request', 'Lobby malformed'); socket.emit('lobby-create-error', err.toError); @@ -133,7 +131,7 @@ function LobbyCreate(socket, args) return; } - // Make sure user doesn't already own a lobby + // Make sure user isn't already in a lobby or owns one if (!Game.Lobbies.CheckUserAvailability(useruid)) { err.addError(400, 'Bad Request', 'User already owns lobby'); @@ -161,7 +159,6 @@ function LobbyCreate(socket, args) return; } - console.log(lobby, lobbyJoined); if (lobbyJoined.uid !== lobby.uid) { err.addError(500, 'Internal Server Error', 'Illegal lobby'); @@ -174,15 +171,87 @@ function LobbyCreate(socket, args) function LobbyJoin(socket, args) { + const err = new Error; + const useruid = args.user.uid; + + if (!useruid) + { + err.addError(400, 'Bad Request', 'Unknown uid'); + socket.emit('lobby-join-error', err.toError); + return; + } + + if (!args.lobbyID || args.joinAsSpectator === undefined) + { + err.addError(400, 'Bad Request', 'Lobby malformed'); + socket.emit('lobby-join-error', err.toError); + return; + } + + // Make sure user is who they say they are + const user = Game.Registrar.GetUserbyConnection(socket.id); + if (!user || user.uid != useruid) + { + err.addError(403, 'Forbidden', 'Illegal user'); + socket.emit('lobby-join-error', err.toError); + return; + } + + // Make sure user isn't already in a lobby + if (!Game.Lobbies.CheckUserAvailability(useruid)) + { + err.addError(400, 'Bad Request', 'User already owns lobby'); + socket.emit('lobby-join-error', err.toError); + return; + } + + const lobby = Game.Lobbies.GetLobbyByUID(args.lobbyID); + if (!lobby) + { + err.addError(400, 'Bad Request', 'Lobby does not exist'); + socket.emit('lobby-join-error', err.toError); + return; + } + + if (args.joinAsSpectator) + { + // TODO + } else + { + const status = Game.Lobbies.UserJoinLobby(lobby.uid, useruid); + + if (!status) + { + err.addError(403, 'Forbidden', 'Cannot join lobby'); + socket.emit('lobby-join-error', err.toError); + return; + } + + socket.emit('lobby-join-success', lobby); + } } +function LobbyLeave(socket, args) +{ + const user = Game.Registrar.GetUserbyConnection(socket.id); + Logger.debug(`USER ${user.uid} (${Game.Registrar.GetUserByUID(user.uid).username}) ATTEMPTING TO LEAVE LOBBY`); + Game.Lobbies.UserLeaveLobby(user.uid); +} + + function HandleDisconnect(socket, args) { - Logger.debug(`${socket.id} DISCONNECTED`); const user = Game.Registrar.GetUserbyConnection(socket.id); if (!user) return; + + // if user is in a lobby, leave and if user own's a lobby, destruct + // leave lobby before user is disconnected + LobbyLeave(socket); + Game.Registrar.UserDisconnect(user.uid); + + Logger.info(`SOCKET ${socket.id} DISCONNECTED`); }