Ejemplo n.º 1
0
        public void AddAI(Session session, JMapData map_data, JGameModeData game_mode)
        {
            var spawn = JsonData.Instance.SpawnPositions[map_data.ID];

            string session_id = Session.GetNewSessionId();
            // todo : AI 닉네임 설정이 필요.
            // 현재 응답에서 중복만 되지 않으면 문제가 없을 것으로 보임
            string user_id = session_id;

            var player = new ServerCommon.PlayerInfo()
            {
                user_no         = session.user_no,
                character_type  = session.character_type,
                user_id         = user_id,
                team            = (byte)spawn[replyToBattleServer.players.Count].spawnTeam,
                is_ai           = true,
                player_id       = replyToBattleServer.players.Count + 1,
                spawn_index     = replyToBattleServer.players.Count,
                character_level = 1,
            };

            replyToBattleServer.players.Add(session_id, player);
            replyToClient.CharacterList.Add(new StartPlayCharacterInfo()
            {
                SelectedCharacter = session.character_type, UserId = user_id, Team = player.team, PlayerId = player.player_id, SpawnIndex = player.spawn_index
            });
        }
Ejemplo n.º 2
0
        public async Task <bool> AddPlayer(Session session, JMapData map_data, JGameModeData game_mode)
        {
            if (replyToBattleServer.players.ContainsKey(session.session_id))
            {
                Log.Error($"AddPlayer duplicate session_id:{session.session_id}");
                return(false);
            }

            List <JSpawnData> spawn;

            if (JsonData.Instance.SpawnPositions.TryGetValue(map_data.ID, out spawn) == false)
            {
                Log.Error($"AddPlayer cannot find map_id:{map_data.ID}");
                return(false);
            }
            if (spawn.Count <= replyToBattleServer.players.Count)
            {
                Log.Error($"AddPlayer cannot find spawn index:{replyToBattleServer.players.Count}, size:{spawn.Count}");
                return(false);
            }
            var team = (byte)spawn[replyToBattleServer.players.Count].spawnTeam;

            int characterLevel = 0;
            var character      = await CharacterCache.Instance.GetEntity(session.member_no, session.character_no, true, false, false);

            if (character != null && character != default(Models.Character))
            {
                characterLevel = character.character_level;
            }

            var player = new ServerCommon.PlayerInfo()
            {
                user_no         = session.user_no,
                character_type  = session.character_type,
                user_id         = session.user_name,
                team            = (byte)team,
                player_id       = replyToBattleServer.players.Count + 1,
                spawn_index     = replyToBattleServer.players.Count,
                character_level = characterLevel,
            };

            replyToBattleServer.players.Add(session.session_id, player);
            replyToClient.CharacterList.Add(new StartPlayCharacterInfo()
            {
                SelectedCharacter = session.character_type, UserId = session.user_name, Team = player.team, PlayerId = player.player_id, SpawnIndex = player.spawn_index
            });
            return(true);
        }
        public static async Task StartPlay(StartPlayRequest request, IServerStreamWriter <StartPlayReply> responseStream, ServerCallContext context)
        {
            Log.Information($"StartPlay mapId:{request.MapId}, SelectedCharacter:{request.SelectedCharacter}, IsImmediatelyJoin{request.IsImmediatelyJoin}");

            var session = await context.GetSession();

            if (session == null)
            {
                await responseStream.WriteAsync(new StartPlayReply()
                {
                    Code = ErrorCode.LostSession
                });

                return;
            }

            // 게임 시작 요청 정보를 캐싱
            await session.UpdateSessionLock(request.SelectedCharacter, request.MapId, true);

            if (request.IsImmediatelyJoin)
            {
                (bool ret, string server_addr, byte worldId, string channel_key, string channel_id) = await Channel.GetAvailableServer(request.MapId);

                if (ret == false)
                {
                    // 전투 가능한 서버가 없다
                    Log.Error($"Cannot find Server user_no:{session.user_no}");
                    await responseStream.WriteAsync(new StartPlayReply()
                    {
                        Code = ErrorCode.BusyServer
                    });

                    return;
                }

                var tmp_players = new Dictionary <string, ServerCommon.PlayerInfo>();
                ServerCommon.PlayerInfo player = new ServerCommon.PlayerInfo()
                {
                    user_no        = session.user_no,
                    character_type = session.character_type,
                    user_id        = session.user_name,
                    team           = (byte)core.MathHelpers.GetRandomInt((int)core.BaseStruggleTeam.TeamCount),
                };
                tmp_players.Add(session.session_id, player);

                var characters = new List <StartPlayCharacterInfo>();
                characters.Add(new StartPlayCharacterInfo()
                {
                    SelectedCharacter = session.character_type, UserId = session.user_name, Team = player.team
                });
                var reply = new StartPlayReply()
                {
                    Code             = ErrorCode.Success,
                    IsStart          = true,
                    BattleServerAddr = server_addr,
                    WorldId          = worldId,
                    MapId            = request.MapId,
                };
                characters.ForEach(x => reply.CharacterList.Add(x));

                await responseStream.WriteAsync(reply);


                await SequentialMatchmaking.PubStartPlay(tmp_players, worldId, channel_id, session);


#pragma warning disable 4014
                Task.Run(async() => await SequentialMatchmaking.WaitGameResult(channel_id));
#pragma warning restore 4014

                return;
            }

            // 다른 플레이어로 인해 매칭이 시작 되었는지 확인
            if ((await SequentialMatchmaking.RestoreMatchUser(session.user_no, responseStream)) == true)
            {
                return;
            }

            // 대기중이 플레이어 찾기
            (var player_list, var players, var character_list, var search_success) = await SequentialMatchmaking.SearchPlayer(session, request);

            if (search_success == true)
            {
                // 게임 시작
                if ((await SequentialMatchmaking.StartPlay(player_list, players, character_list, session, request, responseStream)) == false)
                {
                    // 예약했던 플레이어 취소
                    await SequentialMatchmaking.ClearReservedPlayer(player_list);
                }
                return;
            }

            // 예약했던 플레이어 취소
            await SequentialMatchmaking.ClearReservedPlayer(player_list);

            Log.Information("StartPlay waiting... {0}", session.user_no);

            // 대기
            await SequentialMatchmaking.WaitStartPlay(session, request, responseStream);
        }
        /// <summary>
        /// 매칭 대상 (플레이어) 찾기
        /// </summary>
        /// <param name="session"></param>
        /// <param name="request"></param>
        /// <returns></returns>
        public static async Task <(List <long>, Dictionary <string, ServerCommon.PlayerInfo>, List <StartPlayCharacterInfo>, bool)> SearchPlayer(Session session, StartPlayRequest request)
        {
            var db = Cache.Instance.GetDatabase();

            Lobby.Session player_session = null;
            var           players        = new Dictionary <string, ServerCommon.PlayerInfo>();
            var           character_list = new List <StartPlayCharacterInfo>();
            long          match_id       = 0;
            var           player_list    = new List <long>();
            var           waiting_list   = await db.SortedSetRangeByScoreAsync($"waiting_list:{request.MapId}");

            Log.Information($"waiting user ({string.Join(",", waiting_list)})");
            bool result = false;

            if (waiting_list.Length >= MAX_START_PLAYER_COUNT - 1)
            {
                match_id = await db.StringIncrementAsync("match_instance_id");

                for (int i = 0; i < waiting_list.Length; ++i)
                {
                    long user_no = (long)waiting_list[i];
                    Log.Information($"searching... waiting user {user_no}");
                    // 자신은 스킵
                    if (user_no == session.user_no)
                    {
                        continue;
                    }

                    if ((await db.StringGetAsync($"waiting:{user_no}")).HasValue)
                    {
                        // 매칭에 필요한 유저를 선점한다
                        if (await db.StringSetAsync($"match_user:{user_no}", match_id, match_user_expire, When.NotExists) == true)
                        {
                            player_session = await Session.GetSession(user_no, false);

                            if (player_session == null)
                            {
                                Log.Information("cannot find Session {0}", user_no);
                                await db.KeyDeleteAsync($"match_user:{user_no}");

                                continue;
                            }

                            ServerCommon.PlayerInfo player = new ServerCommon.PlayerInfo()
                            {
                                user_no        = player_session.user_no,
                                character_type = player_session.character_type,
                                user_id        = player_session.user_name,
                                team           = (byte)(players.Count % (int)core.BaseStruggleTeam.TeamCount),
                            };
                            players.Add(player_session.session_id, player);
                            character_list.Add(new StartPlayCharacterInfo()
                            {
                                SelectedCharacter = player_session.character_type, UserId = player_session.user_name, Team = player.team
                            });

                            player_list.Add(user_no);
                            Log.Information($"Candidate User {user_no}");

                            if (player_list.Count == MAX_START_PLAYER_COUNT - 1)
                            {
                                result = true;
                                break;
                            }
                        }
                        else
                        {
                            Log.Information("already other match assign user {0}", user_no);
                        }
                    }
                    else
                    {
                        Log.Information("wait timeout user {0}", user_no);

                        // 유효하지 않는 유저는 대기자 목록에서 삭제한다.
                        await SequentialMatchmaking.RemoveMatchUser(user_no, request.MapId);
                    }
                }
            }

            Log.Information($"StartPlay player_list ({string.Join(",", player_list)})");
            return(player_list, players, character_list, result);
        }
        /// <summary>
        /// 게임 플레이 시작
        /// </summary>
        /// <param name="player_list"></param>
        /// <param name="players"></param>
        /// <param name="character_list"></param>
        /// <param name="session"></param>
        /// <param name="request"></param>
        /// <param name="responseStream"></param>
        /// <returns></returns>
        public static async Task <bool> StartPlay(List <long> player_list, Dictionary <string, ServerCommon.PlayerInfo> players, List <StartPlayCharacterInfo> character_list, Session session, StartPlayRequest request, IServerStreamWriter <StartPlayReply> responseStream)
        {
            // 매칭에 필요한 인원을 모두 찾았을때
            // 전투 가능한 서버를 찾아 세팅
            (bool ret, string server_addr, byte worldId, string channel_key, string channel_id) = await Channel.GetAvailableServer(request.MapId);

            if (ret == false)
            {
                // 전투 가능한 서버가 없다
                Log.Error($"Cannot find Server user_no:{session.user_no}");
                await responseStream.WriteAsync(new StartPlayReply()
                {
                    Code = ErrorCode.BusyServer
                });

                return(false);
            }

            ServerCommon.PlayerInfo player = new ServerCommon.PlayerInfo()
            {
                user_no        = session.user_no,
                character_type = session.character_type,
                user_id        = session.user_name,
                team           = (byte)(players.Count % (int)core.BaseStruggleTeam.TeamCount)
            };
            players.Add(session.session_id, player);

            character_list.Add(new StartPlayCharacterInfo()
            {
                SelectedCharacter = session.character_type, UserId = session.user_name, Team = player.team
            });
            var reply = new StartPlayReply()
            {
                Code             = ErrorCode.Success,
                IsStart          = true,
                BattleServerAddr = server_addr,
                WorldId          = worldId,
                MapId            = request.MapId,
            };

            character_list.ForEach(x => reply.CharacterList.Add(x));


            string reply_str = new JsonFormatter(new JsonFormatter.Settings(true)).Format(reply);

            Log.Information($"StartPlay Reply {reply_str}");

            // 매칭된 유저들에게 알림
            for (int i = 0; i < player_list.Count; ++i)
            {
                await Cache.Instance.GetSubscriber().PublishAsync($"sub_user:{player_list[i]}", reply_str);
            }

            await SequentialMatchmaking.RemoveMatchUser(session.user_no, request.MapId);

            // 배틀서버에 알림
            await PubStartPlay(players, worldId, channel_id, session);

            Log.Information($"StartPlay {session.user_no}, channel_msg:{channel_key}");

            await responseStream.WriteAsync(reply);

            // 매칭이 성공적으로 이루어졌으므로 이후 매칭 결과를 pub/sub으로 전달 받는다.

#pragma warning disable 4014
            Task.Run(async() => await WaitGameResult(channel_id));
#pragma warning restore 4014

            return(true);
        }