UNPKG

reldens

Version:
240 lines (226 loc) 8.96 kB
/** * * Reldens - ActivePlayers * * Singleton registry for tracking all active player sessions across rooms. * Provides multiple lookup indexes: by session ID, user ID, username, player ID, and player name. * Manages the player session lifecycle (add, fetch, remove) for multi-session user support. * */ const { ActivePlayer } = require('./active-player'); const { Logger, sc } = require('@reldens/utils'); /** * @typedef {import('@colyseus/core').Client} Client * @typedef {import('@colyseus/core').Room} Room * * @typedef {Object} UserModel * @property {number} id * @property {string} username * @property {Object} [player] * * @typedef {Object} RoomPlayerIndexes * @property {Object<string, ActivePlayer>} bySessionId * @property {Object<number, string>} byUserId * @property {Object<string, string>} byUserName * @property {Object<number, string>} byPlayerId * @property {Object<string, string>} byPlayerName */ class ActivePlayers { constructor() { /** @type {string} */ this.guestsEmailDomain = ''; /** @type {string} */ this.gameRoomInstanceId = ''; /** @type {Object<string, RoomPlayerIndexes>} */ this.playersByRoomId = {}; /** @type {Object<number, Object<string, string>>} */ this.playersSessionsByUserId = {}; } /** * @param {UserModel} userModel * @param {Client} client * @param {Room} room * @returns {ActivePlayer} Created ActivePlayer instance */ add(userModel, client, room) { let activePlayer = new ActivePlayer({ guestsEmailDomain: this.guestsEmailDomain, userModel, client, roomId: room.roomId, }); if(!this.playersByRoomId[activePlayer.roomId]){ this.playersByRoomId[activePlayer.roomId] = { bySessionId: {}, byUserId: {}, byUserName: {}, byPlayerId: {}, byPlayerName: {}, }; } if(!this.playersByRoomId[activePlayer.roomId].byUserId[userModel.id]){ this.playersByRoomId[activePlayer.roomId].byUserId[userModel.id] = {}; } if(!this.playersByRoomId[activePlayer.roomId].byUserName[userModel.username]){ this.playersByRoomId[activePlayer.roomId].byUserName[userModel.username] = {}; } if(activePlayer.playerId){ this.playersByRoomId[activePlayer.roomId].byPlayerId[activePlayer.playerId] = this.playersByRoomId[activePlayer.roomId].byPlayerName[activePlayer.playerName] = activePlayer.sessionId; } this.playersByRoomId[activePlayer.roomId].byUserId[userModel.id] = this.playersByRoomId[activePlayer.roomId].byUserName[userModel.username] = activePlayer.sessionId; this.playersByRoomId[activePlayer.roomId].bySessionId[activePlayer.sessionId] = activePlayer; if(!this.playersSessionsByUserId[userModel.id]){ this.playersSessionsByUserId[userModel.id] = {}; } this.playersSessionsByUserId[userModel.id][activePlayer.sessionId] = room.roomId; return activePlayer; } /** * @param {string} sessionId * @param {string} roomId * @param {boolean} [withPlayer] * @returns {ActivePlayer|false} ActivePlayer instance or false if not found */ fetchByRoomAndSessionId(sessionId, roomId, withPlayer = false) { if(!sessionId){ //Logger.debug('Missing sessionId on "fetchByRoomAndSessionId".'); return false; } if(!roomId){ //Logger.debug('Missing roomId on "fetchByRoomAndSessionId".'); return false; } // @NOTE: GameRoom instance won't have a player on the user model, this only happens in the RoomScene.onJoin(). if(withPlayer && this.gameRoomInstanceId === roomId){ Logger.warning('Fetching active user withPlayer on gameRoomInstance.'); return false; } let roomPlayersBySessionId = sc.get(this.playersByRoomId[roomId], 'bySessionId'); if(!roomPlayersBySessionId){ Logger.warning('Missing bySessionId on "fetchByRoomAndSessionId".'); return false; } return roomPlayersBySessionId[sessionId]; } /** * @param {string} userName * @param {string} roomId * @param {boolean} [withPlayer] * @returns {ActivePlayer|false} ActivePlayer instance or false if not found */ fetchByRoomAndUserName(userName, roomId, withPlayer = false) { if(!userName){ return false; } if(!roomId){ return false; } // @NOTE: GameRoom instance won't have a player on the user model, this only happens in the RoomScene.onJoin(). if(withPlayer && this.gameRoomInstanceId === roomId){ return false; } let playersByRoomId = this.playersByRoomId[roomId]; let roomPlayersByUserName = sc.get(playersByRoomId, 'byUserName'); if(!roomPlayersByUserName){ return false; } let playerSessionIdInRoom = sc.get(roomPlayersByUserName, userName); if(!playerSessionIdInRoom){ return false; } return this.fetchByRoomAndSessionId(playerSessionIdInRoom, roomId, withPlayer); } /** * @param {number} playerId * @param {string} roomId * @param {boolean} [withPlayer] * @returns {ActivePlayer|false} ActivePlayer instance or false if not found */ fetchByRoomAndPlayerId(playerId, roomId, withPlayer = false) { // @NOTE: GameRoom instance won't have a player on the user model, this only happens in the RoomScene.onJoin(). if(withPlayer && this.gameRoomInstanceId === roomId){ return false; } let roomPlayersByPlayerId = sc.get(this.playersByRoomId[roomId], 'byPlayerId'); if(!roomPlayersByPlayerId){ return false; } let playerSessionIdInRoom = sc.get(roomPlayersByPlayerId, playerId); if(!playerSessionIdInRoom){ return false; } return this.fetchByRoomAndSessionId(playerSessionIdInRoom, roomId, withPlayer); } /** * @param {string} playerName * @param {string} roomId * @param {boolean} [withPlayer] * @returns {ActivePlayer|false} ActivePlayer instance or false if not found */ fetchByRoomAndPlayerName(playerName, roomId, withPlayer = false) { // @NOTE: GameRoom instance won't have a player on the user model, this only happens in the RoomScene.onJoin(). if(withPlayer && this.gameRoomInstanceId === roomId){ return false; } let roomPlayersByPlayerName = sc.get(this.playersByRoomId[roomId], 'byPlayerName'); if(!roomPlayersByPlayerName){ return false; } let playerSessionIdInRoom = sc.get(roomPlayersByPlayerName, playerName); if(!playerSessionIdInRoom){ return false; } return this.fetchByRoomAndSessionId(playerSessionIdInRoom, roomId, withPlayer); } /** * @param {number} userId * @returns {boolean} Returns true if sessions were found and removed, false if the user has no sessions */ removeAllByUserId(userId) { let userRoomsSessions = this.playersSessionsByUserId[userId]; if(!userRoomsSessions){ return false; } let sessionsIds = Object.keys(userRoomsSessions); for(let sessionId in sessionsIds){ this.removeByRoomAndSessionId(sessionId, sessionsIds[sessionId]); } this.playersSessionsByUserId[userId] = {}; return true; } /** * @param {string} sessionId * @param {string} roomId * @returns {boolean} Returns true if the session was found and removed, false if the room or session was not found */ removeByRoomAndSessionId(sessionId, roomId) { let room = this.playersByRoomId[roomId]; if(!room){ return false; } let activePlayer = this.fetchByRoomAndSessionId(sessionId, roomId, false); if(activePlayer){ delete this.playersSessionsByUserId[activePlayer.userId][sessionId]; delete room.byUserId[activePlayer.userId]; delete room.byUserName[activePlayer.username]; delete room.byPlayerId[activePlayer.playerId]; delete room.byPlayerName[activePlayer.playerName]; } delete room.bySessionId[sessionId]; return true; } } module.exports.ActivePlayers = new ActivePlayers();