diff --git a/back/src/Controller/AuthenticateController.ts b/back/src/Controller/AuthenticateController.ts index 6eaa14ca..db5fb1ce 100644 --- a/back/src/Controller/AuthenticateController.ts +++ b/back/src/Controller/AuthenticateController.ts @@ -4,7 +4,7 @@ import {BAD_REQUEST, OK} from "http-status-codes"; import {SECRET_KEY, URL_ROOM_STARTED} from "../Enum/EnvironmentVariable"; //TODO fix import by "_Enum/..." import { uuid } from 'uuidv4'; -export class AuthenticateController{ +export class AuthenticateController { App : Application; constructor(App : Application) { @@ -14,7 +14,8 @@ export class AuthenticateController{ //permit to login on application. Return token to connect on Websocket IO. login(){ - this.App.post("/login", (req: Request, res: Response) => { + // For now, let's completely forget the /login route. + /*this.App.post("/login", (req: Request, res: Response) => { let param = req.body; if(!param.email){ return res.status(BAD_REQUEST).send({ @@ -29,6 +30,6 @@ export class AuthenticateController{ mapUrlStart: URL_ROOM_STARTED, userId: userId, }); - }); + });*/ } -} \ No newline at end of file +} diff --git a/back/src/Controller/IoSocketController.ts b/back/src/Controller/IoSocketController.ts index d3410a13..6349b352 100644 --- a/back/src/Controller/IoSocketController.ts +++ b/back/src/Controller/IoSocketController.ts @@ -14,6 +14,7 @@ import {UserInterface} from "_Model/UserInterface"; enum SockerIoEvent { CONNECTION = "connection", DISCONNECT = "disconnect", + ATTRIBUTE_USER_ID = "attribute-user-id", // Sent from server to client just after the connexion is established to give the client its unique id. JOIN_ROOM = "join-room", USER_POSITION = "user-position", WEBRTC_SIGNAL = "webrtc-signal", @@ -33,7 +34,8 @@ export class IoSocketController { this.Io = socketIO(server); // Authentication with token. it will be decoded and stored in the socket. - this.Io.use((socket: Socket, next) => { + // Completely commented for now, as we do not use the "/login" route at all. + /*this.Io.use((socket: Socket, next) => { if (!socket.handshake.query || !socket.handshake.query.token) { return next(new Error('Authentication error')); } @@ -47,7 +49,7 @@ export class IoSocketController { (socket as ExSocketInterface).token = tokenDecoded; next(); }); - }); + });*/ this.ioConnection(); this.shareUsersPosition(); @@ -74,6 +76,7 @@ export class IoSocketController { let userId = lastUser.id; let client: ExSocketInterface|null = this.searchClientById(userId); if (client === null) { + console.warn('Could not find client ', userId, ' in group') return; } let roomId = client.roomId; @@ -180,7 +183,6 @@ export class IoSocketController { socket.leave(Client.webRtcRoomId); //delete all socket information - delete Client.userId; delete Client.webRtcRoomId; delete Client.roomId; delete Client.token; @@ -190,6 +192,9 @@ export class IoSocketController { console.error(e); } }); + + // Let's send the user id to the user + socket.emit(SockerIoEvent.ATTRIBUTE_USER_ID, socket.id); }); } @@ -201,11 +206,12 @@ export class IoSocketController { let clients: Array = Object.values(this.Io.sockets.sockets); for (let i = 0; i < clients.length; i++) { let client: ExSocketInterface = clients[i]; - if (client.userId !== userId) { - continue + if (client.id !== userId) { + continue; } return client; } + console.log("Could not find user with id ", userId); return null; } @@ -216,7 +222,7 @@ export class IoSocketController { let clients: Array = Object.values(this.Io.sockets.sockets); for (let i = 0; i < clients.length; i++) { let client: ExSocketInterface = clients[i]; - if (client.userId !== userId) { + if (client.id !== userId) { continue } return client; @@ -230,7 +236,7 @@ export class IoSocketController { */ sendDisconnectedEvent(Client: ExSocketInterface) { Client.broadcast.emit(SockerIoEvent.WEBRTC_DISCONNECT, JSON.stringify({ - userId: Client.userId + userId: Client.id })); //disconnect webrtc room @@ -248,14 +254,16 @@ export class IoSocketController { leaveRoom(Client : ExSocketInterface){ //lease previous room and world if(Client.roomId){ - //user leave previous room - Client.leave(Client.roomId); //user leave previous world let world : World|undefined = this.Worlds.get(Client.roomId); if(world){ + console.log('Entering world.leave') world.leave(Client); - this.Worlds.set(Client.roomId, world); + //this.Worlds.set(Client.roomId, world); } + //user leave previous room + Client.leave(Client.roomId); + delete Client.roomId; } } /** @@ -293,7 +301,7 @@ export class IoSocketController { }); }); //join world - world.join(messageUserPosition); + world.join(Client, messageUserPosition); this.Worlds.set(messageUserPosition.roomId, world); } @@ -322,11 +330,11 @@ export class IoSocketController { clients.forEach((client: ExSocketInterface, index: number) => { let clientsId = clients.reduce((tabs: Array, clientId: ExSocketInterface, indexClientId: number) => { - if (!clientId.userId || clientId.userId === client.userId) { + if (!clientId.id || clientId.id === client.id) { return tabs; } tabs.push({ - userId: clientId.userId, + userId: clientId.id, name: clientId.name, initiator: index <= indexClientId }); @@ -341,7 +349,7 @@ export class IoSocketController { saveUserInformation(socket: ExSocketInterface, message: MessageUserPosition) { socket.position = message.position; socket.roomId = message.roomId; - socket.userId = message.userId; + //socket.userId = message.userId; socket.name = message.name; socket.character = message.character; } @@ -354,9 +362,9 @@ export class IoSocketController { } rooms.refreshUserPosition(rooms, this.Io); - // update position in the worl + // update position in the world let data = { - userId: Client.userId, + userId: Client.id, roomId: Client.roomId, position: Client.position, name: Client.name, @@ -367,7 +375,7 @@ export class IoSocketController { if (!world) { return; } - world.updatePosition(messageUserPosition); + world.updatePosition(Client, messageUserPosition); this.Worlds.set(messageUserPosition.roomId, world); } diff --git a/back/src/Model/Websocket/ExSocketInterface.ts b/back/src/Model/Websocket/ExSocketInterface.ts index 22cd29c2..c55a9759 100644 --- a/back/src/Model/Websocket/ExSocketInterface.ts +++ b/back/src/Model/Websocket/ExSocketInterface.ts @@ -1,11 +1,12 @@ import {Socket} from "socket.io"; import {PointInterface} from "./PointInterface"; +import {Identificable} from "./Identificable"; -export interface ExSocketInterface extends Socket { +export interface ExSocketInterface extends Socket, Identificable { token: any; roomId: string; webRtcRoomId: string; - userId: string; + //userId: string; name: string; character: string; position: PointInterface; diff --git a/back/src/Model/Websocket/ExtRooms.ts b/back/src/Model/Websocket/ExtRooms.ts index 7fb6216d..43395a28 100644 --- a/back/src/Model/Websocket/ExtRooms.ts +++ b/back/src/Model/Websocket/ExtRooms.ts @@ -22,7 +22,7 @@ let RefreshUserPositionFunction = function(rooms : ExtRooms, Io: socketIO.Server continue; } let data = { - userId: socket.userId, + userId: socket.id, roomId: socket.roomId, position: socket.position, name: socket.name, diff --git a/back/src/Model/Websocket/Identificable.ts b/back/src/Model/Websocket/Identificable.ts new file mode 100644 index 00000000..8c344259 --- /dev/null +++ b/back/src/Model/Websocket/Identificable.ts @@ -0,0 +1,3 @@ +export interface Identificable { + id: string; +} diff --git a/back/src/Model/Websocket/Message.ts b/back/src/Model/Websocket/Message.ts index ccf5d287..f4bdead8 100644 --- a/back/src/Model/Websocket/Message.ts +++ b/back/src/Model/Websocket/Message.ts @@ -16,6 +16,7 @@ export class Message { } toJson() { + return { userId: this.userId, roomId: this.roomId, diff --git a/back/src/Model/World.ts b/back/src/Model/World.ts index 72bf029c..19e8c194 100644 --- a/back/src/Model/World.ts +++ b/back/src/Model/World.ts @@ -5,6 +5,7 @@ import {Distance} from "./Distance"; import {UserInterface} from "./UserInterface"; import {ExSocketInterface} from "_Model/Websocket/ExSocketInterface"; import {PositionInterface} from "_Model/PositionInterface"; +import {Identificable} from "_Model/Websocket/Identificable"; export type ConnectCallback = (user: string, group: Group) => void; export type DisconnectCallback = (user: string, group: Group) => void; @@ -14,17 +15,17 @@ export type GroupUpdatedCallback = (group: Group) => void; export type GroupDeletedCallback = (uuid: string, lastUser: UserInterface) => void; export class World { - private minDistance: number; - private groupRadius: number; + private readonly minDistance: number; + private readonly groupRadius: number; // Users, sorted by ID - private users: Map; - private groups: Group[]; + private readonly users: Map; + private readonly groups: Group[]; - private connectCallback: ConnectCallback; - private disconnectCallback: DisconnectCallback; - private groupUpdatedCallback: GroupUpdatedCallback; - private groupDeletedCallback: GroupDeletedCallback; + private readonly connectCallback: ConnectCallback; + private readonly disconnectCallback: DisconnectCallback; + private readonly groupUpdatedCallback: GroupUpdatedCallback; + private readonly groupDeletedCallback: GroupDeletedCallback; constructor(connectCallback: ConnectCallback, disconnectCallback: DisconnectCallback, @@ -47,25 +48,29 @@ export class World { return this.groups; } - public join(userPosition: MessageUserPosition): void { - this.users.set(userPosition.userId, { - id: userPosition.userId, + public join(socket : Identificable, userPosition: MessageUserPosition): void { + this.users.set(socket.id, { + id: socket.id, position: userPosition.position }); // Let's call update position to trigger the join / leave room - this.updatePosition(userPosition); + this.updatePosition(socket, userPosition); } - public leave(user : ExSocketInterface){ + public leave(user : Identificable){ let userObj = this.users.get(user.id); - if (userObj !== undefined && typeof userObj.group !== 'undefined') { - this.leaveGroup(user); + if (userObj === undefined) { + // FIXME: this seems always wrong. I guess user.id is different from userPosition.userId + console.warn('User ', user.id, 'does not belong to world! It should!'); } - this.users.delete(user.userId); + if (userObj !== undefined && typeof userObj.group !== 'undefined') { + this.leaveGroup(userObj); + } + this.users.delete(user.id); } - public updatePosition(userPosition: MessageUserPosition): void { - let user = this.users.get(userPosition.userId); + public updatePosition(socket : Identificable, userPosition: MessageUserPosition): void { + let user = this.users.get(socket.id); if(typeof user === 'undefined') { return; } @@ -118,7 +123,6 @@ export class World { throw new Error("The user is part of no group"); } group.leave(user); - if (group.isEmpty()) { this.groupDeletedCallback(group.getId(), user); group.destroy(); diff --git a/back/tests/WorldTest.ts b/back/tests/WorldTest.ts index 57f0f3f4..148e7383 100644 --- a/back/tests/WorldTest.ts +++ b/back/tests/WorldTest.ts @@ -17,36 +17,36 @@ describe("World", () => { let world = new World(connect, disconnect, 160, 160, () => {}, () => {}); - world.join(new MessageUserPosition({ - userId: "foo", + world.join({ id: "foo" }, new MessageUserPosition({ + userId: "foofoo", roomId: 1, position: new Point(100, 100) })); - world.join(new MessageUserPosition({ - userId: "bar", + world.join({ id: "bar" }, new MessageUserPosition({ + userId: "barbar", roomId: 1, position: new Point(500, 100) })); - world.updatePosition(new MessageUserPosition({ - userId: "bar", + world.updatePosition({ id: "bar" }, new MessageUserPosition({ + userId: "barbar", roomId: 1, position: new Point(261, 100) })); expect(connectCalledNumber).toBe(0); - world.updatePosition(new MessageUserPosition({ - userId: "bar", + world.updatePosition({ id: "bar" }, new MessageUserPosition({ + userId: "barbar", roomId: 1, position: new Point(101, 100) })); expect(connectCalledNumber).toBe(2); - world.updatePosition(new MessageUserPosition({ - userId: "bar", + world.updatePosition({ id: "bar" }, new MessageUserPosition({ + userId: "barbar", roomId: 1, position: new Point(102, 100) })); @@ -64,14 +64,14 @@ describe("World", () => { let world = new World(connect, disconnect, 160, 160, () => {}, () => {}); - world.join(new MessageUserPosition({ - userId: "foo", + world.join({ id: "foo" }, new MessageUserPosition({ + userId: "foofoo", roomId: 1, position: new Point(100, 100) })); - world.join(new MessageUserPosition({ - userId: "bar", + world.join({ id: "bar" }, new MessageUserPosition({ + userId: "barbar", roomId: 1, position: new Point(200, 100) })); @@ -80,16 +80,16 @@ describe("World", () => { connectCalled = false; // baz joins at the outer limit of the group - world.join(new MessageUserPosition({ - userId: "baz", + world.join({ id: "baz" }, new MessageUserPosition({ + userId: "bazbaz", roomId: 1, position: new Point(311, 100) })); expect(connectCalled).toBe(false); - world.updatePosition(new MessageUserPosition({ - userId: "baz", + world.updatePosition({ id: "baz" }, new MessageUserPosition({ + userId: "bazbaz", roomId: 1, position: new Point(309, 100) })); @@ -109,14 +109,14 @@ describe("World", () => { let world = new World(connect, disconnect, 160, 160, () => {}, () => {}); - world.join(new MessageUserPosition({ - userId: "foo", + world.join({ id: "foo" }, new MessageUserPosition({ + userId: "foofoo", roomId: 1, position: new Point(100, 100) })); - world.join(new MessageUserPosition({ - userId: "bar", + world.join({ id: "bar" }, new MessageUserPosition({ + userId: "barbar", roomId: 1, position: new Point(259, 100) })); @@ -124,16 +124,16 @@ describe("World", () => { expect(connectCalled).toBe(true); expect(disconnectCallNumber).toBe(0); - world.updatePosition(new MessageUserPosition({ - userId: "bar", + world.updatePosition({ id: "bar" }, new MessageUserPosition({ + userId: "barbar", roomId: 1, position: new Point(100+160+160+1, 100) })); expect(disconnectCallNumber).toBe(2); - world.updatePosition(new MessageUserPosition({ - userId: "bar", + world.updatePosition({ id: "bar" }, new MessageUserPosition({ + userId: "barbar", roomId: 1, position: new Point(262, 100) })); diff --git a/front/src/Connexion.ts b/front/src/Connexion.ts index d6d37025..f29bef2e 100644 --- a/front/src/Connexion.ts +++ b/front/src/Connexion.ts @@ -18,7 +18,8 @@ enum EventMessage{ GROUP_DELETE = "group-delete", CONNECT_ERROR = "connect_error", - RECONNECT = "reconnect" + RECONNECT = "reconnect", + ATTRIBUTE_USER_ID = "attribute-user-id" // Sent from server to client just after the connexion is established to give the client its unique id. } class Message { @@ -184,25 +185,37 @@ export class Connexion implements ConnexionInterface { * @param characterSelected */ createConnexion(characterSelected: string): Promise { - return Axios.post(`${API_URL}/login`, {email: this.email}) + /*return Axios.post(`${API_URL}/login`, {email: this.email}) .then((res) => { this.token = res.data.token; - this.userId = res.data.userId; + this.userId = res.data.userId;*/ this.socket = SocketIo(`${API_URL}`, { - query: { + /*query: { token: this.token - } + }*/ }); this.connectSocketServer(); - return res.data; + // TODO: maybe trigger promise only when connexion is established? + let promise = new Promise((resolve, reject) => { + /*console.log('PROMISE CREATED') + this.socket.on('connection', () => { + console.log('CONNECTED'); + resolve(this); + });*/ + resolve(this); + }); + + return promise; + + /* return res.data; }) .catch((err) => { console.error(err); throw err; - }); + });*/ } /** @@ -229,6 +242,7 @@ export class Connexion implements ConnexionInterface { } //listen event + this.attributeUserId(); this.positionOfAllUser(); this.disconnectServer(); this.errorMessage(); @@ -286,6 +300,15 @@ export class Connexion implements ConnexionInterface { this.socket.emit(EventMessage.USER_POSITION, messageUserPosition.toString()); } + attributeUserId(): void { + // This event is received as soon as the connexion is established. + // It allows informing the browser of its own user id. + this.socket.on(EventMessage.ATTRIBUTE_USER_ID, (userId: string) => { + console.log('Received my user id: ', userId); + this.userId = userId; + }); + } + /** * The data sent is an array with information for each user : * [ diff --git a/front/src/Phaser/Game/GameManager.ts b/front/src/Phaser/Game/GameManager.ts index 6a4381dd..b886de9e 100644 --- a/front/src/Phaser/Game/GameManager.ts +++ b/front/src/Phaser/Game/GameManager.ts @@ -67,7 +67,7 @@ export class GameManager { */ createCurrentPlayer(): void { //Get started room send by the backend - this.currentGameScene.createCurrentPlayer(this.ConnexionInstance.userId); + this.currentGameScene.createCurrentPlayer(); this.status = StatusGameManagerEnum.CURRENT_USER_CREATED; } @@ -119,6 +119,10 @@ export class GameManager { return this.playerName; } + getPlayerId(): string { + return this.ConnexionInstance.userId; + } + getCharacterSelected(): string { return this.characterUserSelected; } diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index 7b32e3ef..1e4d1e6e 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -15,7 +15,7 @@ export enum Textures { export interface GameSceneInterface extends Phaser.Scene { Map: Phaser.Tilemaps.Tilemap; - createCurrentPlayer(UserId : string) : void; + createCurrentPlayer() : void; shareUserPosition(UsersPosition : Array): void; shareGroupPosition(groupPositionMessage: GroupCreatedUpdatedMessageInterface): void; updateOrCreateMapPlayer(UsersPosition : Array): void; @@ -266,11 +266,11 @@ export class GameScene extends Phaser.Scene implements GameSceneInterface, Creat }) } - createCurrentPlayer(UserId : string){ + createCurrentPlayer(){ //initialise player //TODO create animation moving between exit and strat this.CurrentPlayer = new Player( - UserId, + null, // The current player is not has no id (because the id can change if connexion is lost and we should check that id using the GameManager. this, this.startX, this.startY, @@ -347,9 +347,11 @@ export class GameScene extends Phaser.Scene implements GameSceneInterface, Creat return; } + let currentPlayerId = this.GameManager.getPlayerId(); + //add or create new user UsersPosition.forEach((userPosition : MessageUserPositionInterface) => { - if(userPosition.userId === this.CurrentPlayer.userId){ + if(userPosition.userId === currentPlayerId){ return; } let player = this.findPlayerInMap(userPosition.userId); diff --git a/front/src/Phaser/Login/LogincScene.ts b/front/src/Phaser/Login/LogincScene.ts index ea21e9f5..f7dd0029 100644 --- a/front/src/Phaser/Login/LogincScene.ts +++ b/front/src/Phaser/Login/LogincScene.ts @@ -90,7 +90,7 @@ export class LogincScene extends Phaser.Scene implements GameSceneInterface { }); /*create user*/ - this.createCurrentPlayer("test"); + this.createCurrentPlayer(); cypressAsserter.initFinished(); } @@ -144,7 +144,7 @@ export class LogincScene extends Phaser.Scene implements GameSceneInterface { throw new Error("Method not implemented."); } - createCurrentPlayer(UserId: string): void { + createCurrentPlayer(): void { for (let i = 0; i