コード例 #1
0
        public override ErrorCode TryGetRandomGame(JoinRandomGameRequest joinRequest, ILobbyPeer peer, out GameState gameState, out string message)
        {
            message = null;

            foreach (GameState game in this.gameDict)
            {
                if (!game.IsOpen || !game.IsVisible || !game.HasBeenCreatedOnGameServer || (game.MaxPlayer > 0 && game.PlayerCount >= game.MaxPlayer))
                {
                    continue;
                }

                if (joinRequest.GameProperties != null && game.MatchGameProperties(joinRequest.GameProperties) == false)
                {
                    continue;
                }

                if (game.CheckUserIdOnJoin &&
                    (game.ContainsUser(peer.UserId) ||
                     game.IsUserInExcludeList(peer.UserId) ||
                     !game.CheckSlots(peer.UserId, joinRequest.AddUsers)))
                {
                    continue;
                }


                gameState = game;
                return(ErrorCode.Ok);
            }

            gameState = null;
            return(ErrorCode.NoMatchFound);
        }
コード例 #2
0
ファイル: SqlGameList.cs プロジェクト: theGameShop/Flipper
        public override ErrorCode TryGetRandomGame(JoinRandomGameRequest joinRequest, ILobbyPeer peer, out GameState gameState, out string message)
        {
            message = null;

            if (this.gameDict.Count == 0)
            {
                gameState = null;
                return(ErrorCode.NoMatchFound);
            }

            if (string.IsNullOrEmpty(joinRequest.QueryData))
            {
                var node = this.gameDict.First;
                while (node != null)
                {
                    gameState = node.Value;
                    if (gameState.IsJoinable)
                    {
                        if (!gameState.CheckUserIdOnJoin ||
                            (!gameState.ContainsUser(peer.UserId) &&
                             !gameState.IsUserInExcludeList(peer.UserId) &&
                             gameState.CheckSlots(peer.UserId, joinRequest.AddUsers)))
                        {
                            return(ErrorCode.Ok);
                        }
                    }

                    node = node.Next;
                }

                gameState = null;
                return(ErrorCode.NoMatchFound);
            }

            string id;

            try
            {
                id = this.gameDatabase.FindMatch(joinRequest.QueryData);
            }
            catch (System.Data.Common.DbException sqlException)
            {
                gameState = null;
                message   = sqlException.Message;
                return(ErrorCode.OperationInvalid);
            }

            if (string.IsNullOrEmpty(id))
            {
                gameState = null;
                return(ErrorCode.NoMatchFound);
            }

            if (!this.gameDict.TryGet(id, out gameState))
            {
                return(ErrorCode.NoMatchFound);
            }

            return(ErrorCode.Ok);
        }
コード例 #3
0
        public OperationResponse HandleJoinRandomGame(OperationRequest operationRequest, SendParameters sendParameters)
        {
            var joinRandomGameRequest = new JoinRandomGameRequest(this.Protocol, operationRequest);

            OperationResponse response;

            if (OperationHelper.ValidateOperation(joinRandomGameRequest, log, out response) == false)
            {
                return(response);
            }

            if (string.IsNullOrEmpty(joinRandomGameRequest.LobbyName) && this.AppLobby != null)
            {
                this.AppLobby.EnqueueOperation(this, operationRequest, sendParameters);
                return(null);
            }

            AppLobby lobby;

            if (!this.Application.LobbyFactory.GetOrCreateAppLobby(joinRandomGameRequest.LobbyName, (AppLobbyType)joinRandomGameRequest.LobbyType, out lobby))
            {
                return(new OperationResponse {
                    OperationCode = operationRequest.OperationCode, ReturnCode = (int)ErrorCode.OperationDenied, DebugMessage = "Lobby does not exist"
                });
            }

            lobby.EnqueueOperation(this, operationRequest, sendParameters);
            return(null);
        }
コード例 #4
0
        private bool TryGetRandomGame(LinkedListNode <GameState> startNode, JoinRandomGameRequest joinRequest, ILobbyPeer peer, out GameState gameState)
        {
            var node = startNode;

            do
            {
                var game = node.Value;
                node = node.Next ?? this.gameDict.First;

                if (!IsGameJoinable(joinRequest, peer, game))
                {
                    continue;
                }

                if (joinRequest.GameProperties != null && game.MatchGameProperties(joinRequest.GameProperties) == false)
                {
                    continue;
                }

                if (log.IsDebugEnabled)
                {
                    log.DebugFormat("Found match. Next start node gameid={0}", node.Value.Id);
                }

                this.nextJoinRandomStartNode = node;
                gameState = game;
                return(true);
            }while (node != startNode);

            gameState = null;
            return(false);
        }
コード例 #5
0
        public virtual OperationResponse HandleJoinRandomGame(OperationRequest operationRequest, SendParameters sendParameters)
        {
            var response = this.CheckJoinActivity(operationRequest);

            if (response != null)
            {
                return(response);
            }

            var joinRandomGameRequest = new JoinRandomGameRequest(this.Protocol, operationRequest);

            if (OperationHelper.ValidateOperation(joinRandomGameRequest, log, out response) == false)
            {
                return(response);
            }

            AppLobby lobby;

            response = this.TryGetLobby(joinRandomGameRequest.LobbyName,
                                        joinRandomGameRequest.LobbyType, operationRequest.OperationCode, out lobby);
            if (response != null)
            {
                return(response);
            }

            this.IncConcurrentJoinRequest(1);
            lobby.EnqueueOperation(this, operationRequest, sendParameters);

            return(null);
        }
コード例 #6
0
ファイル: NunitClient.cs プロジェクト: JasoonS/TotalTempo2
        public JoinRandomGameResponse JoinRandomGame(JoinRandomGameRequest request, short expectedResult, params string[] expectedRoomNames)
        {
            var operationRequest = new OperationRequest();

            operationRequest.OperationCode = OperationCode.JoinRandomGame;
            operationRequest.Parameters    = new Dictionary <byte, object>();

            if (request.GameProperties != null)
            {
                operationRequest.Parameters[ParameterCode.GameProperties] = request.GameProperties;
            }

            if (request.QueryData != null)
            {
                operationRequest.Parameters[(byte)Operations.ParameterCode.Data] = request.QueryData;
            }

            if (request.JoinRandomType != 0)
            {
                operationRequest.Parameters[ParameterCode.MatchMakingType] = request.JoinRandomType;
            }

            if (request.LobbyName != null)
            {
                operationRequest.Parameters[(byte)Operations.ParameterCode.LobbyName] = request.LobbyName;
            }

            if (request.LobbyType != 0)
            {
                operationRequest.Parameters[(byte)Operations.ParameterCode.LobbyType] = request.LobbyType;
            }

            var response           = this.SendRequestAndWaitForResponse(operationRequest, expectedResult);
            var joinRandomResponse = GetJoinRandomGameResponse(response);

            if (expectedResult != ErrorCode.Ok)
            {
                return(joinRandomResponse);
            }

            if (expectedRoomNames == null || expectedRoomNames.Length == 0)
            {
                return(joinRandomResponse);
            }

            foreach (var id in expectedRoomNames)
            {
                if (id == joinRandomResponse.GameId)
                {
                    return(joinRandomResponse);
                }
            }

            Assert.Fail("Unexpected game on join random: gameId={0}", joinRandomResponse.GameId);
            return(joinRandomResponse);
        }
コード例 #7
0
        private void JoinRandom(Hashtable properties)
        {
            if (log.IsDebugEnabled)
            {
                log.Debug("MASTER: Joining random game ...");
            }

            var operation = new JoinRandomGameRequest {
                GameProperties = properties
            };
            var request = new OperationRequest((byte)Operations.OperationCode.JoinRandomGame, operation);

            this.masterClient.SendOperationRequest(request, new SendParameters());
        }
コード例 #8
0
ファイル: AppLobby.cs プロジェクト: JasoonS/TotalTempo2
        protected virtual OperationResponse HandleJoinRandomGame(MasterClientPeer peer, OperationRequest operationRequest)
        {
            // validate the operation request
            var operation = new JoinRandomGameRequest(peer.Protocol, operationRequest);
            OperationResponse response;

            if (OperationHelper.ValidateOperation(operation, log, out response) == false)
            {
                return(response);
            }

            // special handling for game properties send by AS3/Flash (Amf3 protocol) clients
            if (peer.Protocol.ProtocolType == ProtocolType.Amf3V152 || peer.Protocol.ProtocolType == ProtocolType.Json)
            {
                Utilities.ConvertAs3WellKnownPropertyKeys(operation.GameProperties, null);
            }

            // try to find a match
            GameState game;
            string    errorMessage;
            var       result = this.GameList.TryGetRandomGame((JoinRandomType)operation.JoinRandomType, peer, operation.GameProperties, operation.QueryData, out game, out errorMessage);

            if (result != ErrorCode.Ok)
            {
                if (string.IsNullOrEmpty(errorMessage))
                {
                    errorMessage = "No match found";
                }

                response = new OperationResponse {
                    OperationCode = operationRequest.OperationCode, ReturnCode = (short)result, DebugMessage = errorMessage
                };
                return(response);
            }

            // match found, add peer to game and notify the peer
            game.AddPeer(peer);

            if (log.IsDebugEnabled)
            {
                log.DebugFormat("Found match: connectionId={0}, userId={1}, gameId={2}", peer.ConnectionId, peer.UserId, game.Id);
            }

            this.ScheduleCheckJoinTimeOuts();

            object joinResponse = this.GetJoinRandomGameResponse(peer, game);

            return(new OperationResponse(operationRequest.OperationCode, joinResponse));
        }
コード例 #9
0
        protected static bool IsGameJoinable(JoinRandomGameRequest joinRequest, ILobbyPeer peer, GameState gameState)
        {
            if (!gameState.IsJoinable)
            {
                return(false);
            }

            if (!gameState.SupportsProtocol(peer.NetworkProtocol))
            {
                return(false);
            }

            return(!gameState.CheckUserIdOnJoin ||
                   (!gameState.ContainsUser(peer.UserId) &&
                    !gameState.IsUserInExcludeList(peer.UserId) &&
                    gameState.CheckSlots(peer.UserId, joinRequest.AddUsers)));
        }
コード例 #10
0
        public JoinRandomGameResponse JoinRandomGame(Hashtable gameProperties, byte maxPlayers, Hashtable actorProperties,
                                                     MatchmakingMode mode, string lobbyName, AppLobbyType lobbyType, string sqlLobbyFilter, short errorCode = ErrorCode.Ok)
        {
            var request = new JoinRandomGameRequest
            {
                GameProperties = new Hashtable(),
                JoinRandomType = (byte)mode,
                LobbyType      = (byte)lobbyType,
                LobbyName      = lobbyName,
            };

            if (maxPlayers > 0)
            {
                request.GameProperties.Add(GamePropertyKey.MaxPlayers, maxPlayers);
            }
            return(this.JoinRandomGame(request, errorCode));
        }
コード例 #11
0
        private ErrorCode TryGetRandomGame(string queryData, JoinRandomGameRequest joinRequest, ILobbyPeer peer, out GameState gameState, out string message)
        {
            message = null;

            int skipCount = 0;

            while (true)
            {
                string id;
                try
                {
                    id = this.gameDatabase.FindMatch(queryData, skipCount++);
                }
                catch (DbException sqlException)
                {
                    gameState = null;
                    message   = sqlException.Message;
                    return(ErrorCode.OperationInvalid);
                }

                if (string.IsNullOrEmpty(id))
                {
                    gameState = null;
                    return(ErrorCode.NoMatchFound);
                }

                if (!this.gameDict.TryGet(id, out gameState))
                {
                    return(ErrorCode.NoMatchFound);
                }

                if (IsGameJoinable(joinRequest, peer, gameState))
                {
                    if (log.IsDebugEnabled)
                    {
                        log.Debug($"Random Game '{gameState}', CheckUserOnJoin:{gameState.CheckUserIdOnJoin}, " +
                                  $"UserLists: {gameState.GetUserListsAsString()} Properties:{ValueToString.ToString(gameState.ToHashTable())}" +
                                  $"is joinable for request: {ValueToString.OperationToString(joinRequest.OperationRequest)}, Joining User:{peer.UserId}");
                    }
                    return(ErrorCode.Ok);
                }
            }
        }
コード例 #12
0
        protected virtual OperationResponse HandleJoinRandomGame(MasterClientPeer peer, OperationRequest operationRequest)
        {
            // validate the operation request
            var operation = new JoinRandomGameRequest(peer.Protocol, operationRequest);
            OperationResponse response;

            if (OperationHelper.ValidateOperation(operation, log, out response) == false)
            {
                return(response);
            }

            // try to find a match
            GameState game;
            string    errorMessage;
            var       result = this.GameList.TryGetRandomGame(operation, peer, out game, out errorMessage);

            if (result != ErrorCode.Ok)
            {
                if (string.IsNullOrEmpty(errorMessage))
                {
                    errorMessage = "No match found";
                }

                response = new OperationResponse {
                    OperationCode = operationRequest.OperationCode, ReturnCode = (short)result, DebugMessage = errorMessage
                };
                return(response);
            }

            // match found, add peer to game and notify the peer
            game.AddPeer(peer);

            if (log.IsDebugEnabled)
            {
                log.DebugFormat("Found match: connectionId={0}, userId={1}, gameId={2}", peer.ConnectionId, peer.UserId, game.Id);
            }

            this.ScheduleCheckJoinTimeOuts();

            object joinResponse = this.GetJoinRandomGameResponse(peer, game);

            return(new OperationResponse(operationRequest.OperationCode, joinResponse));
        }
コード例 #13
0
        private ErrorCode GetFirstJoinableGame(JoinRandomGameRequest joinRequest, ILobbyPeer peer, out GameState gameState)
        {
            var node = this.gameDict.First;

            while (node != null)
            {
                gameState = node.Value;
                if (IsGameJoinable(joinRequest, peer, gameState))
                {
                    log.Debug($"First Joinable Game '{gameState}', CheckUserOnJoin:{gameState.CheckUserIdOnJoin}, " +
                              $"UserLists: {gameState.GetUserListsAsString()} Properties:{ValueToString.ToString(gameState.ToHashTable())}" +
                              $"is joinable for request: {ValueToString.OperationToString(joinRequest.OperationRequest)}, Joining User:{peer.UserId}");
                    return(ErrorCode.Ok);
                }

                node = node.Next;
            }

            gameState = null;
            return(ErrorCode.NoMatchFound);
        }
コード例 #14
0
ファイル: GameList.cs プロジェクト: cernysw/UnityDemo
        private bool TryGetRandomGame(LinkedListNode <GameState> startNode, JoinRandomGameRequest joinRequest, ILobbyPeer peer, out GameState gameState)
        {
            var node = startNode;

            do
            {
                var game = node.Value;
                node = node.Next ?? this.gameDict.First;

                if (!game.IsOpen || !game.IsVisible || !game.HasBeenCreatedOnGameServer || (game.MaxPlayer > 0 && game.PlayerCount >= game.MaxPlayer))
                {
                    continue;
                }

                if (joinRequest.GameProperties != null && game.MatchGameProperties(joinRequest.GameProperties) == false)
                {
                    continue;
                }

                if (game.CheckUserIdOnJoin &&
                    (game.ContainsUser(peer.UserId) ||
                     game.IsUserInExcludeList(peer.UserId) ||
                     !game.CheckSlots(peer.UserId, joinRequest.AddUsers)))
                {
                    continue;
                }

                if (log.IsDebugEnabled)
                {
                    log.DebugFormat("Found match. Next start node gameid={0}", node.Value.Id);
                }

                this.nextJoinRandomStartNode = node;
                gameState = game;
                return(true);
            }while (node != startNode);

            gameState = null;
            return(false);
        }
コード例 #15
0
        public OperationResponse HandleJoinRandomGame(OperationRequest operationRequest, SendParameters sendParameters)
        {
            var joinRandomGameRequest = new JoinRandomGameRequest(this.Protocol, operationRequest);

            OperationResponse response;

            if (OperationHelper.ValidateOperation(joinRandomGameRequest, log, out response) == false)
            {
                return(response);
            }

            AppLobby lobby;

            response = this.TryGetLobby(joinRandomGameRequest.LobbyName,
                                        joinRandomGameRequest.LobbyType, operationRequest.OperationCode, out lobby);
            if (response != null)
            {
                return(response);
            }

            lobby.EnqueueOperation(this, operationRequest, sendParameters);
            return(null);
        }
コード例 #16
0
ファイル: GameList.cs プロジェクト: cernysw/UnityDemo
        public override ErrorCode TryGetRandomGame(JoinRandomGameRequest joinRequest, ILobbyPeer peer, out GameState gameState, out string message)
        {
            message = null;

            if (this.gameDict.Count == 0)
            {
                gameState = null;
                return(ErrorCode.NoMatchFound);
            }

            LinkedListNode <GameState> startNode;

            switch ((JoinRandomType)joinRequest.JoinRandomType)
            {
            default:
            case JoinRandomType.FillRoom:
                startNode = this.gameDict.First;
                break;

            case JoinRandomType.SerialMatching:
                startNode = this.nextJoinRandomStartNode ?? this.gameDict.First;
                break;

            case JoinRandomType.RandomMatching:
                var startNodeIndex = this.rnd.Next(this.gameDict.Count);
                startNode = this.gameDict.GetAtIndex(startNodeIndex);
                break;
            }

            if (!TryGetRandomGame(startNode, joinRequest, peer, out gameState))
            {
                return(ErrorCode.NoMatchFound);
            }

            return(ErrorCode.Ok);
        }
コード例 #17
0
ファイル: GameListBase.cs プロジェクト: theGameShop/Flipper
 public abstract ErrorCode TryGetRandomGame(JoinRandomGameRequest joinRequest, ILobbyPeer peer, out GameState gameState, out string message);
コード例 #18
0
        public override ErrorCode TryGetRandomGame(JoinRandomGameRequest joinRequest, ILobbyPeer peer, out GameState gameState, out string message)
        {
            message   = null;
            gameState = null;

            if (this.gameDict.Count == 0)
            {
//                gameState = null;
                return(ErrorCode.NoMatchFound);
            }

            if (string.IsNullOrEmpty(joinRequest.QueryData))
            {
                return(GetFirstJoinableGame(joinRequest, peer, out gameState));

//                var node = this.gameDict.First;
//                while (node != null)
//                {
//                    gameState = node.Value;
//                    if (IsGameJoinable(joinRequest, peer, gameState))
//                    {
//                        return ErrorCode.Ok;
//                    }
//
//                    node = node.Next;
//                }
//
////                gameState = null;
//                return ErrorCode.NoMatchFound;
            }

            if (!useStoredProcedures)
            {
                //remove last semicolon, otherwise we have another (empty) query after split
                if (joinRequest.QueryData.EndsWith(";"))
                {
                    joinRequest.QueryData = joinRequest.QueryData.Remove(joinRequest.QueryData.Length - 1);
                }

                var splitQueries = joinRequest.QueryData.Split(';');
                //create a setting for max numbers of queries?
                if (splitQueries.Length > 3)
                {
                    //create entry in ErrorMessages?
                    message = "Max queries allowed: 3";
                    return(ErrorCode.OperationInvalid);
                }

                foreach (var query in splitQueries)
                {
                    if (string.IsNullOrEmpty(query))
                    {
                        //error or ignore?
                        continue;

//                        message = "Query was empty";
//                        return ErrorCode.OperationInvalid;
                    }

                    var result = TryGetRandomGame(query, joinRequest, peer, out gameState, out message);
                    if (result != ErrorCode.NoMatchFound)
                    {
                        //match or error
                        return(result);
                    }
                }

                //no match, check options
//                return joinRequest.JoinRandomType == (byte)JoinRandomType.JoinRandomOnSqlNoMatch
//                    ? GetFirstJoinableGame(joinRequest, peer, out gameState)
//                    : ErrorCode.NoMatchFound;

                return(ErrorCode.NoMatchFound);

//                return TryGetRandomGame(joinRequest.QueryData, joinRequest, peer, out gameState, out message);
            }

            //obsolete soon
            //TODO const
            //TODO decide stored procedure prefix
            var spPrefix = "$SP.";

            var spName = joinRequest.QueryData;

            //temp, until the prefix is removed
            if (joinRequest.QueryData.StartsWith(spPrefix, StringComparison.InvariantCultureIgnoreCase))
            {
                spName = joinRequest.QueryData.Substring(spPrefix.Length).ToLower();
            }

            if (!storedProcedures.ContainsKey(spName) || string.IsNullOrEmpty(storedProcedures[spName]))
            {
                if (log.IsDebugEnabled)
                {
                    log.DebugFormat("Stored procedure '{0}' not found", spName);
                }

                message = "Stored procedure not found";
                return(ErrorCode.OperationInvalid);
            }

            var queryData = storedProcedures[spName];

            //TODO const
            //TODO decide value
//            var authCookiePlaceholderPrefix = "$ac.";
            const char placeholderStart = '[';
            const char placeholderEnd   = ']';

            //replace placeholder values from AuthCookie
            //just call string.Replace for all values in the AuthCookie?
            var masterClientPeer = (MasterClientPeer)peer;

            queryData = ReplacePlaceholderIgnoreCase(queryData, masterClientPeer.AuthCookie);

//            if (queryData.IndexOf(authCookiePlaceholderPrefix, StringComparison.InvariantCultureIgnoreCase) >= 0)
            if (queryData.IndexOf(placeholderStart) >= 0 || queryData.IndexOf(placeholderEnd) >= 0)
            {
                if (log.IsDebugEnabled)
                {
                    log.DebugFormat("Stored procedure '{0}' contains placeholder entries not found in AuthCookie", spName);
                }

                message = "Stored procedure contains placeholder entries not found in AuthCookie";
                return(ErrorCode.OperationInvalid);
            }

            //strip last semicolon in case one was added to end of stored procedure > already done when reading file
//            if (queryData.EndsWith(";"))
//            {
//                queryData = queryData.Substring(0, queryData.Length - 1);
//            }

            //TODO decide delimiter. using semicolon means that funnels can only be used with stored procedures (if client sends semicolon a NotAllowedSemicolonInQuereyData is returned)
            var queries = queryData.Split(';');

            var errorCode = ErrorCode.NoMatchFound;

            //TODO const
            //TODO max number of queries
            var limit = 10;

            for (int i = 0; i < queries.Length; i++)
            {
                if (log.IsDebugEnabled)
                {
                    log.DebugFormat("Searching match, index {0}, query '{1}'", i, queries[i]);
                }

                errorCode = TryGetRandomGame(queries[i], joinRequest, peer, out gameState, out message);

                if (errorCode != ErrorCode.NoMatchFound || i >= limit - 1)
                {
                    break;
                }
            }

            return(errorCode);
        }
コード例 #19
0
        public JoinRandomGameResponse JoinRandomGame(JoinRandomGameRequest request, short expectedResult, params string[] expectedRoomNames)
        {
            var operationRequest = CreateOperationRequest(OperationCode.JoinRandomGame);

            if (request.GameProperties != null)
            {
                operationRequest.Parameters[ParameterCode.GameProperties] = request.GameProperties;
            }

            if (request.QueryData != null)
            {
                operationRequest.Parameters[ParameterCode.Data] = request.QueryData;
            }

            if (request.JoinRandomType != 0)
            {
                operationRequest.Parameters[ParameterCode.MatchMakingType] = request.JoinRandomType;
            }

            if (request.LobbyName != null)
            {
                operationRequest.Parameters[ParameterCode.LobbyName] = request.LobbyName;
            }

            if (request.LobbyType != 0)
            {
                operationRequest.Parameters[ParameterCode.LobbyType] = request.LobbyType;
            }

            if (request.AddUsers != null)
            {
                operationRequest.Parameters[ParameterCode.Add] = request.AddUsers;
            }

            var response = this.SendRequestAndWaitForResponse(operationRequest, expectedResult);

            this.authenticationScheme.HandleAuthenticateResponse(this, response.Parameters);

            var joinRandomResponse = GetJoinRandomGameResponse(response);

            if (expectedResult != ErrorCode.Ok)
            {
                return(joinRandomResponse);
            }

            if (expectedRoomNames == null || expectedRoomNames.Length == 0)
            {
                return(joinRandomResponse);
            }

            foreach (var id in expectedRoomNames)
            {
                if (id == joinRandomResponse.GameId)
                {
                    return(joinRandomResponse);
                }
            }

            Assert.Fail("Unexpected game on join random: gameId={0}", joinRandomResponse.GameId);
            return(joinRandomResponse);
        }
コード例 #20
0
        protected virtual OperationResponse HandleJoinRandomGame(MasterClientPeer peer, OperationRequest operationRequest)
        {
            // validate the operation request
            var operation = new JoinRandomGameRequest(peer.Protocol, operationRequest);
            OperationResponse response;

            if (OperationHelper.ValidateOperation(operation, log, out response) == false)
            {
                return(response);
            }

            // try to find a match
            GameState game;
            string    errorMessage;
            var       result = this.GameList.TryGetRandomGame(operation, peer, out game, out errorMessage);

            //create game
            if (result == ErrorCode.NoMatchFound && operation.CreateIfNotExists)
            {
                //random GameId if not set
                if (string.IsNullOrEmpty(operation.GameId))
                {
                    operation.GameId = Guid.NewGuid().ToString();
                    operationRequest.Parameters[(byte)ParameterKey.GameId] = operation.GameId;
                }

                //replace GameProperties (used for filter) with values for game creation
                if (operation.Properties != null)
                {
                    operationRequest.Parameters[(byte)ParameterKey.GameProperties] = operation.Properties;
                }

                //create - we try to use current HandleCreateGame implementation
                var createGameResponse = HandleCreateGame(peer, operationRequest);

                if (createGameResponse.ReturnCode != 0)
                {
                    return(new OperationResponse {
                        OperationCode = operationRequest.OperationCode, ReturnCode = createGameResponse.ReturnCode, DebugMessage = createGameResponse.DebugMessage
                    });
                }

                var joinRandomGameResponse = new JoinRandomGameResponse
                {
                    GameId  = operation.GameId,
                    Address = (string)createGameResponse.Parameters[(byte)ParameterKey.Address],
                };
                //NodeId is not used anywhere atm
                if (createGameResponse.Parameters.ContainsKey((byte)ParameterKey.NodeId))
                {
                    joinRandomGameResponse.NodeId = (byte)createGameResponse.Parameters[(byte)ParameterKey.NodeId];
                }

                return(new OperationResponse(operationRequest.OperationCode, joinRandomGameResponse)
                {
                    //TODO other ReturnCode if game was created
                    ReturnCode = (byte)ErrorCode.Ok
                });
            }

            if (result != ErrorCode.Ok)
            {
                if (string.IsNullOrEmpty(errorMessage))
                {
                    errorMessage = "No match found";
                }

                response = new OperationResponse {
                    OperationCode = operationRequest.OperationCode, ReturnCode = (short)result, DebugMessage = errorMessage
                };
                return(response);
            }

            // match found, add peer to game and notify the peer
            game.AddPeer(peer);

            if (log.IsDebugEnabled)
            {
                log.DebugFormat("Found match: connectionId={0}, userId={1}, gameId={2}", peer.ConnectionId, peer.UserId, game.Id);
            }

            this.ScheduleCheckJoinTimeOuts();

            var joinResponse = this.GetJoinRandomGameResponse(peer, game);

            return(new OperationResponse(operationRequest.OperationCode, joinResponse));
        }