/// <summary>
        ///     Create a match making request
        /// </summary>
        /// <param name="method">The type of request we're making (join, create, etc)</param>
        /// <param name="roomName">The name of the room we're trying to match</param>
        /// <param name="options">Dictionary of options to use in the match making process</param>
        /// <param name="headers">Dictionary of headers to pass to the server</param>
        /// <typeparam name="T">Type of <see cref="ColyseusRoom{T}" /> we want to match with</typeparam>
        /// <returns><see cref="ColyseusRoom{T}" /> we have matched with via async task</returns>
        /// <exception cref="Exception">Thrown if there is a network related error</exception>
        /// <exception cref="CSAMatchMakeException">Thrown if there is an error in the match making process on the server side</exception>
        protected async Task <ColyseusRoom <T> > CreateMatchMakeRequest <T>(string method, string roomName,
                                                                            Dictionary <string, object> options, Dictionary <string, string> headers)
        {
            if (options == null)
            {
                options = new Dictionary <string, object>();
            }

            if (headers == null)
            {
                headers = new Dictionary <string, string>();
            }

            string json = await ColyseusRequest.Request("POST", $"matchmake/{method}/{roomName}", options, headers);

            LSLog.Log($"Server Response: {json}");
            ColyseusMatchMakeResponse response =
                JsonUtility.FromJson <ColyseusMatchMakeResponse>(json /*req.downloadHandler.text*/);

            if (response == null)
            {
                throw new Exception($"Error with request: {json}");
            }

            if (!string.IsNullOrEmpty(response.error))
            {
                throw new CSAMatchMakeException(response.code, response.error);
            }

            return(await ConsumeSeatReservation <T>(response, headers));
        }
        /// <summary>
        ///     Consume the seat reservation
        /// </summary>
        /// <param name="response">The response from the matchmaking attempt</param>
        /// <param name="headers">Dictionary of headers to pass to the server</param>
        /// <typeparam name="T">Type of <see cref="ColyseusRoom{T}" /> we're consuming the seat from</typeparam>
        /// <returns><see cref="ColyseusRoom{T}" /> in which we now have a seat via async task</returns>
        public async Task <ColyseusRoom <T> > ConsumeSeatReservation <T>(ColyseusMatchMakeResponse response,
                                                                         Dictionary <string, string> headers = null)
        {
            ColyseusRoom <T> room = new ColyseusRoom <T>(response.room.name)
            {
                Id        = response.room.roomId,
                SessionId = response.sessionId
            };

            Dictionary <string, object> queryString = new Dictionary <string, object>();

            queryString.Add("sessionId", room.SessionId);

            room.SetConnection(CreateConnection(response.room.processId + "/" + room.Id, queryString, headers));

            TaskCompletionSource <ColyseusRoom <T> > tcs = new TaskCompletionSource <ColyseusRoom <T> >();

            void OnError(int code, string message)
            {
                room.OnError -= OnError;
                tcs.SetException(new CSAMatchMakeException(code, message));
            }

            void OnJoin()
            {
                room.OnError -= OnError;
                tcs.TrySetResult(room);
            }

            room.OnError += OnError;
            room.OnJoin  += OnJoin;

            onAddRoom?.Invoke(room);

            return(await tcs.Task);
        }