diff --git a/TODO b/TODO
index 840f749..c49fc89 100644
--- a/TODO
+++ b/TODO
@@ -2,17 +2,22 @@
[ ] Add support for sharding / load balancing with Nginx
[ ] Use a database lol
+[ ] Lobby discovery system to find and join "public" lobbies
+ [ ] Matchmaking
+
+
# Short term, coursework scope
[ ] Translate
- ✔ Portuagese @done(21-04-11 01:03)
- ✔ Spanish @done(21-04-11 01:03)
- → French
- → Czech
+ ✔ Portuagese (Ines) @done(21-04-11 01:03)
+ ✔ Spanish (Ines) @done(21-04-11 01:03)
+ → French (Alexendro)
+ → Czech (Mikdore)
+
[ ] Sort out how intents work in game transitioning
[ ] Game logic
✘ Singleplayer game logic - OUT OF SCOPE @cancelled(21-04-11 01:04)
-
+ ✘ AI CPU player @cancelled(21-04-11 01:07)
\ No newline at end of file
diff --git a/client/public/game/lobbies.js b/client/public/game/lobbies.js
index 8f323a5..b90bced 100644
--- a/client/public/game/lobbies.js
+++ b/client/public/game/lobbies.js
@@ -240,13 +240,11 @@ socket.on('request-intent-change', obj => {
if (!obj.intent) return;
if (!obj.lobby) return;
- if (!obj.intent === 'GAMETRANSITION') return;
+ if (obj.intent !== 'GAMETRANSITION') return;
// window.location.search = `?uid=${obj.lobby.uid}`;
// window.location.pathname = '/scrabble';
window.location = `/scrabble?uid=${obj.lobby.uid}`;
-
-
});
socket.on('lobby-update', obj => {
diff --git a/client/public/scrabble/events.js b/client/public/scrabble/events.js
index f2638f5..26ed5b0 100644
--- a/client/public/scrabble/events.js
+++ b/client/public/scrabble/events.js
@@ -3,7 +3,6 @@ const gameinfoLeft = document.querySelector('#game-info-left');
const gameinfoCompact = document.querySelector('#game-info-compact');
-
function windowResize()
{
if (window.innerWidth < 1100)
diff --git a/client/public/scrabble/index.html b/client/public/scrabble/index.html
index 27b7b16..00836a3 100644
--- a/client/public/scrabble/index.html
+++ b/client/public/scrabble/index.html
@@ -5,6 +5,8 @@
+
+
@@ -21,6 +23,7 @@
SCRABBLE
+
:
+ :
diff --git a/client/public/scrabble/network.js b/client/public/scrabble/network.js
index 6ef4bcc..9f9d6e1 100644
--- a/client/public/scrabble/network.js
+++ b/client/public/scrabble/network.js
@@ -1,15 +1,109 @@
-
-// is game singleplayer?
const urlParser = new URLSearchParams(window.location.search);
+const ConnectionState = document.querySelector('#connection-state');
+
+
+function initMultiplayer()
+{
+ // init socket
+ const socket = io(window.location.host);
+
+ socket.on('connect', (...args) => {
+ console.log('Socket Connected');
+ ConnectionState.innerHTML = `${localeString('status')}: Waiting for identify`;
+ });
+
+ socket.on('disconnect', (...args) => {
+ console.log('Socket Disconnected');
+ ConnectionState.innerHTML = `${localeString('status')}: ${localeString('status-disconnected')}`;
+ onDisconnect();
+ });
+
+
+ socket.on('identify', (...args) => {
+ ConnectionState.innerHTML = 'Identify recived'
+
+ if (!sessionStorage.user)
+ {
+ socket.disconnect();
+ ConnectionState.innerHTML = 'Identify cannot proceed, no user';
+ document.location.href += '../';
+ return;
+ }
+
+ let user = {};
+ try
+ {
+ user = JSON.parse(sessionStorage.user);
+ } catch (e)
+ {
+ socket.disconnect();
+ ConnectionState.innerHTML = 'Identify cannot proceed, corrupted user';
+ document.location.href += '../';
+ return;
+ }
+
+ if (!user.uid)
+ {
+ socket.disconnect();
+ ConnectionState.innerHTML = 'Identify cannot proceed, corrupted user';
+ document.location.href += '../';
+ return;
+ }
+
+ const lobbyUID = urlParser.get('uid')
+
+ if (!lobbyUID)
+ {
+ socket.disconnect();
+ ConnectionState.innerHTML = 'Identify cannot proceed, corrupted lobby';
+ document.location.href += '../';
+ return;
+ }
+
+ socket.emit('identify', { userid: user.uid, lobbyuid: lobbyUID, intent: 'GAME' });
+ ConnectionState.innerHTML = 'Identify response';
+ });
+
+
+ socket.on('identify-success', (...args) => {
+ console.log(args[0]);
+ ConnectionState.innerHTML = localeString('status-connected-as') + ' ' + args[0].user.username;
+ onConnect();
+ });
+
+ socket.on('identify-error', (...args) => {
+ console.log(args[0]);
+ ConnectionState.innerHTML = JSON.stringify(args[0]);
+ onDisconnect();
+ });
+
+}
+
+
+function onConnect()
+{
+
+}
+
+function onDisconnect()
+{
+
+}
+
+
+
+// is game singleplayer?
let isSingleplayer = false;
if (urlParser.get('uid') === null)
{
isSingleplayer = true;
}
-if (!isSingleplayer)
+if (isSingleplayer)
{
- // init socket
+ ConnectionState.innerHTML = localeString('no-connection-singleplayer');
+} else
+{
+ initMultiplayer();
}
-
diff --git a/data/en.lang b/data/en.lang
index d0668fc..aa10f6c 100644
--- a/data/en.lang
+++ b/data/en.lang
@@ -1,6 +1,7 @@
language:en
country:Britain
----
+
button-back:back; (Action) to go back (a page)
button-create:create
button-join:join; (Action) to join
@@ -14,6 +15,7 @@ error-bad-intent:Client has no intent
error-bold:ERROR
error-cannot-join-lobby:Cannot join lobby
error-creating-lobby:An error occurred while creating the lobby
+error-illegal-intent:Illegal intent
error-illegal-lobby:Illegal lobby
error-illegal-user:Illegal user
error-invalid-username:Invalid username
@@ -48,6 +50,7 @@ lobby-private:private lobby
log-console:log console
message:message; (noun) piece of text
name:name
+no-connection-singleplayer:No connection, playing singleplayer; there is no (connection) as the user is playing (on their own)
players:Players
ready:ready ; (Action) to be (ready) to play
scrabble-name:Scrabble
diff --git a/data/es.lang b/data/es.lang
index 70ab713..2632e9d 100644
--- a/data/es.lang
+++ b/data/es.lang
@@ -14,6 +14,7 @@ error-bad-intent:Cliente no tiene intención
error-bold:ERRO
error-cannot-join-lobby:No se puede unir al lobby
error-creating-lobby:Ocurrió un error al crear el lobby
+error-illegal-intent:
error-illegal-lobby:Lobby ilegal
error-illegal-user:Usuario ilegal
error-invalid-username:Nombre de usuario no es válido
@@ -48,6 +49,7 @@ lobby-private:lobby privado
log-console:consola de log
message:mensaje
name:nombre
+no-connection-singleplayer:
players:Jugadores
ready:
scrabble-name:Scrabble
diff --git a/data/locale.json b/data/locale.json
index 39882d5..149f805 100644
--- a/data/locale.json
+++ b/data/locale.json
@@ -64,6 +64,11 @@
"es": "Ocurrió un error al crear el lobby",
"pt": "Ocorreu um erro ao criar o lobby"
},
+ "error-illegal-intent": {
+ "en": "Illegal intent",
+ "es": "",
+ "pt": ""
+ },
"error-illegal-lobby": {
"en": "Illegal lobby",
"es": "Lobby ilegal",
@@ -234,6 +239,11 @@
"es": "nombre",
"pt": "nome"
},
+ "no-connection-singleplayer": {
+ "en": "No connection, playing singleplayer",
+ "es": "",
+ "pt": ""
+ },
"players": {
"en": "Players",
"es": "Jugadores",
diff --git a/data/pt.lang b/data/pt.lang
index e65568a..c49fce7 100644
--- a/data/pt.lang
+++ b/data/pt.lang
@@ -14,6 +14,7 @@ error-bad-intent:Cliente não tem intenção
error-bold:ERROR
error-cannot-join-lobby:Não é possível entrar no lobby
error-creating-lobby:Ocorreu um erro ao criar o lobby
+error-illegal-intent:
error-illegal-lobby:Lobby ilegal
error-illegal-user:Usuário ilegal
error-invalid-username:Nome de usuário Inválido
@@ -48,6 +49,7 @@ lobby-private:lobby privado
log-console:console de log
message:mensagem
name:nome
+no-connection-singleplayer:
players:Jogadores
ready:
scrabble-name:Scrabble
diff --git a/server/src/game-registrar.js b/server/src/game-registrar.js
index b8afce9..b3cfaab 100644
--- a/server/src/game-registrar.js
+++ b/server/src/game-registrar.js
@@ -158,14 +158,15 @@ function GetUserbyConnection(connectionid)
}
// TODO: User intent
-function UserConnect(useruid, connectionid)
+function UserConnect(useruid, connectionid, intent)
{
if (OnlineUsers[useruid].state === 'CONNECTED') return 'error-taken-user-connection';
OnlineUsers[useruid].connectionid = connectionid;
OnlineUsers[useruid].state = 'CONNECTED';
+ OnlineUsers[useruid].intent = intent;
- Logger.game(`SOCKET ${connectionid} IDENTIFIED AS ${useruid} (${OnlineUsers[useruid].username})`);
+ Logger.game(`SOCKET ${connectionid} IDENTIFIED AS ${useruid} (${OnlineUsers[useruid].username}) INTENDS TO ${intent}`);
return true;
}
diff --git a/server/src/lobbies.js b/server/src/lobbies.js
index 1cffce6..2e06f56 100644
--- a/server/src/lobbies.js
+++ b/server/src/lobbies.js
@@ -8,7 +8,7 @@ LOBBY OBJECT
uid: uid,
name: string
owneruid: useruid,
- players: [{uid, name, ready}],
+ players: [{uid, name, ready, ingame}],
spectators: [{uid, name}],
// PUBLIC, PRIVATE
visibility: 'PUBLIC',
@@ -74,13 +74,18 @@ function IsLobbyReady(lobbyuid)
if (!Lobbies[lobbyuid]) return false;
// only support 2-4 players
// https://en.wikipedia.org/wiki/Scrabble
- // TODO: ADD THIS BACK - REMOVED FOR TESTING
+ // TODO: URGENT ADD THIS BACK AFTER TESTING
// if (Lobbies[lobbyuid].players.length <= 1) return false;
if (Lobbies[lobbyuid].players.length > 4) return false;
return Lobbies[lobbyuid].players.every(e => e.ready);
}
+function IsLobbyReadyForGame(lobbyuid)
+{
+ if (!Lobbies[lobbyuid]) return false;
+ return Lobbies[lobbyuid].players.every(e => e.ingame);
+}
function GetLobbyByUID(lobbyuid)
@@ -95,14 +100,14 @@ function GetLobbyByOwnerUID(owneruid)
return false;
}
-function GetLobbyByUserUID(playeruid)
+function GetLobbyByUserUID(useruid)
{
for (const lobby in Lobbies)
{
for (const player of Lobbies[lobby].players)
- if (player.uid === playeruid) return Lobbies[lobby];
+ if (player.uid === useruid) return Lobbies[lobby];
for (const player of Lobbies[lobby].spectators)
- if (player.uid === playeruid) return Lobbies[lobby];
+ if (player.uid === useruid) return Lobbies[lobby];
}
return false;
@@ -155,7 +160,12 @@ function UserJoinLobby(lobbyuid, useruid, callback)
// TODO: check users and change lobby status
const user = Registrar.GetUserByUID(useruid);
- Lobbies[lobbyuid].players.push({uid: useruid, name: user.username, ready: false});
+ Lobbies[lobbyuid].players.push({
+ uid: useruid,
+ name: user.username,
+ ready: false,
+ ingame: false
+ });
Logger.game(`LOBBY ${lobbyuid} USER ${useruid} (${user.username}) JOINING`);
@@ -238,6 +248,24 @@ function SpectatorJoinLobby(lobbyuid, useruid, callback)
}
+function UserConnectGame(useruid)
+{
+ if (!IsUserInLobby(useruid)) return false;
+
+ const lobby = GetLobbyByUserUID(useruid);
+
+ for (const player in Lobbies[lobby.uid].players)
+ if (Lobbies[lobby.uid].players[player].uid === useruid)
+ Lobbies[lobby.uid].players[player].ingame = true;
+
+
+ for (const spectator in Lobbies[lobby.uid].spectators)
+ if (Lobbies[lobby.uid].spectators[player].uid === useruid)
+ Lobbies[lobby.uid].spectators[spectator].ingame = true;
+
+ return true;
+}
+
module.exports = {
// Lobby validation exports
@@ -245,6 +273,7 @@ module.exports = {
DoesUserOwnLobby: DoesUserOwnLobby,
IsUserInLobby: IsUserInLobby,
IsLobbyReady: IsLobbyReady,
+ IsLobbyReadyForGame: IsLobbyReadyForGame,
// Get lobby exports
GetLobbyByUID: GetLobbyByUID,
@@ -259,5 +288,6 @@ module.exports = {
UserReady: UserReady,
UserUnReady: UserUnReady,
UserLeaveLobby: UserLeaveLobby,
- SpectatorJoinLobby: SpectatorJoinLobby
+ SpectatorJoinLobby: SpectatorJoinLobby,
+ UserConnectGame: UserConnectGame
}
diff --git a/server/src/socketserver.js b/server/src/socketserver.js
index a35569f..55fa4af 100644
--- a/server/src/socketserver.js
+++ b/server/src/socketserver.js
@@ -76,13 +76,6 @@ function ClientIdentify(socket, args)
const user = Game.Registrar.GetUserByUID(args.userid);
const intent = args.intent;
- if (!intent)
- {
- err.addError(400, 'Bad Request', 'error-bad-intent');
- socket.emit('identify-error', err.toError);
- return;
- }
-
if (!user)
{
err.addError(400, 'Bad Request', 'error-unknown-uid');
@@ -90,14 +83,47 @@ function ClientIdentify(socket, args)
return;
}
- // TODO: Sort out client intent
-
- const status = Game.Registrar.UserConnect(user.uid, socket.id);
+ if (!intent)
+ {
+ err.addError(400, 'Bad Request', 'error-bad-intent');
+ socket.emit('identify-error', err.toError);
+ return;
+ }
+
+ const oldIntent = user.intent;
+
+ Game.Registrar.ChangeUserIntent(user.uid, intent);
+ const status = Game.Registrar.UserConnect(user.uid, socket.id, intent);
+
+ // If the user enters a game without transitioning, no bueno
+ if (intent === 'GAME' && oldIntent !== 'GAMETRANSITION')
+ {
+ err.addError(500, 'Internal Server Error', 'error-illegal-intent');
+ socket.emit('identify-error', err.toError);
+ return;
+ }
+
+ // User intends to enter a game
+ if (intent === 'GAME' && oldIntent === 'GAMETRANSITION')
+ {
+ const lobbyUID = args.lobbyuid;
+
+ // Make sure the user is actually in this game
+ const lobby = Game.Lobbies.GetLobbyByUserUID(user.uid);
+ if (lobby.uid !== lobbyUID)
+ {
+ err.addError(500, 'Internal Server Error', 'error-illegal-intent');
+ socket.emit('identify-error', err.toError);
+ return;
+ }
+
+ Game.Lobbies.UserConnectGame(user.uid);
+ }
+
if (status === true)
{
socket.emit('identify-success', {connected: true, user: user});
- Game.Registrar.ChangeUserIntent(user.uid, intent);
return;
}
else if (status === 'error-taken-user-connection')
@@ -319,7 +345,11 @@ function HandleDisconnect(socket, args)
// if user is in a lobby, leave and if user own's a lobby, destruct
// leave lobby before user is disconnected
- LobbyLeave(socket);
+
+ if (user.intent !== 'GAMETRANSITION')
+ {
+ LobbyLeave(socket);
+ }
Game.Registrar.UserDisconnect(user.uid);