Home Reference Source

src/server/utils/matchmaker.js

import { generateID, GLOBAL } from '../../client/js/global'
import { getField, setField } from '../server'
import { getTeamColors } from './serverutils'
import { initRoom } from './serverinit'

/**
 * Matchmaking system for public matches. Runs after initial socket.io server connection, but before connecting to a server.
 * @param {*} socket socket.io instance. INDEPENDENT OF PLAYER (any valid socket connection can go here!!!!!)
 * @param {string} room Name of room
 * @param {string} team Name of team
 * @returns The new room that has been assigned
 */
export function roomMatchmaker (socket, room, team) {
	let validJoin = false // This join attempt was valid.
	let roomType = socket.handshake.query.roomType

	// Make sure the room you are trying to join is valid
	if (room !== GLOBAL.NO_ROOM_IDENTIFIER && getField(['rooms', room]) !== undefined && !getField(['rooms', room]).joinable && getField(['rooms', room]) !== undefined) { // Room full
		socket.emit('connectionError', { msg: 'The room ' + room + ' has started or is full!' })
	}

	if (team !== GLOBAL.NO_TEAM_IDENTIFIER && getField(['teams', team]) !== undefined && getField(['teams', team]).room !== undefined) {
		// Make sure everything is compatible
		if (getField(['rooms', getField(['teams', team]).room]) !== undefined && getField(['rooms', getField(['teams', team]).room]).type !== roomType) { // Wrong room type
			socket.emit('connectionError', { msg: 'Your team is playing in a ' + getField('rooms', getField(['teams', team]).room).type + ' room, but you are trying to join a ' + roomType + ' room!' })
		}
		else if (!getField(['teams', team, 'joinable'])) { // Team full
			console.log(getField(['teams']))
			socket.emit('connectionError', { msg: 'Your team is already in game or full!' })
		}
		else { // is joinable
			validJoin = true
			room = getField(['teams', team, 'room'])

			if (((roomType === '2v2v2v2' || roomType === '2v2') && getField(['teams', team, 'players']).length === 2) || getField(['teams', team, 'players']).length === 4) {
				setField(false, ['teams', team, 'joinable'])
			}
		}
	}
	// Team not found or need to join a random team
	else {
		// Try joining a room
		for (let roomName in getField(['rooms'])) {
			if (roomName.indexOf(roomType) > -1) {
				// Auto team
				if (team === GLOBAL.NO_TEAM_IDENTIFIER) {
					for (let i = 0; i < 4; i++) {
						if (getField(['rooms', roomName, 'teams', room + i]) && getField(['rooms', roomName, 'teams', room + i, 'joinable'])) {
							room = roomName
							team = room + i
						}
					}

					// No random teams are joinable- test if this room is full or not
					if (team === GLOBAL.NO_TEAM_IDENTIFIER) {
						if (((roomType === '4v4v4v4' || roomType === '2v2v2v2') && getField(['rooms', roomName, 'teams']).length < 4) || getField(['rooms', roomName, 'teams']).length < 2) {
							room = roomName
							team = room + '_' + (getField(['rooms', roomName, 'teams']).length)
						}
					}
				}
				// Custom team
				else if (((roomType === '4v4v4v4' || roomType === '2v2v2v2') && getField(['rooms', roomName, 'teams']).length < 4) || getField(['rooms', roomName, 'teams']).length < 2) {
					room = roomName
				}
			}
		}

		// No matching rooms - must create a new room
		if (room === GLOBAL.NO_ROOM_IDENTIFIER) {
			room = 'NA_' + roomType + '_' + generateID()
			if (team === GLOBAL.NO_TEAM_IDENTIFIER) {
				team = room + '_0'
			}
		}

		// Custom room auto team
		if (team === GLOBAL.NO_TEAM_IDENTIFIER) {
			for (let i = 0; i < 4; i++) {
				if (getField(['rooms', room]) && getField(['rooms', room, 'teams', room + '_' + i]) && getField(['rooms', room, 'teams', room + '_' + i, 'joinable'])) {
					team = room + i
				}
			}
		}
		// No random teams are joinable make a new team in custom room
		if (team === GLOBAL.NO_TEAM_IDENTIFIER) {
			try {
				team = room + '_' + (getField(['rooms', room, 'teams']).length)
			}
			catch (e) {
				team = room + '_0'
			}
		}

		// Make team
		setField({
			room: room,
			players: [],
			joinable: true
		}, ['teams', team])

		validJoin = true
	}

	// Join custom room
	if (validJoin) {
		// Set up room if it does not exist
		if (getField(['rooms', room]) === undefined || getField(['rooms', room]) === null) {
			initRoom(socket, room)
		}

		// Add player to team
		// Equivalent to rooms[room].teams.push({ name: team });
		getField(['teams', team, 'players']).push(socket.id)
		// Instantiate team in the room if it has not been done already
		if (getField(['teams', team, 'players']).length === 1) {
			// Equivalent to teams[socket.handshake.query.team].players.push(socket.id);
			getField(['rooms', room, 'teams']).push({ name: team, players: [socket.id] })
		}

		// console.log(getField(['rooms', room, 'teams']))
		socket.join(room, () => {
			console.log('[Server] '.bold.blue + `Player ${socket.handshake.query.name} (${socket.id}) joined room ${room} in team ${team}`.yellow)
		})
	}

	return { room: room, team: team }
}