/// <summary> /// 매칭 조건이 맞지 않아 대기 /// </summary> /// <param name="session"></param> /// <param name="request"></param> /// <param name="responseStream"></param> /// <returns></returns> public static async Task WaitStartPlay(Session session, StartPlayRequest request, IServerStreamWriter <StartPlayReply> responseStream) { // 대기자로 등록 await MatchUser.RemoveMatchUser(session.user_no); await WaitingList.AddWaitingUser(new WaitingUser() { map_id = session.map_id, rank = session.rank }, session.user_no); }
/// <summary> /// 매칭 조건이 맞지 않아 대기 /// </summary> /// <param name="session"></param> /// <param name="request"></param> /// <param name="responseStream"></param> /// <returns></returns> public static async Task WaitStartPlay(Session session, StartPlayRequest request, IServerStreamWriter <StartPlayReply> responseStream) { var db = Cache.Instance.GetDatabase(); // 대기자로 등록 await db.KeyDeleteAsync($"match_user:{session.user_no}"); // 매칭 선점 클리어 await db.SortedSetAddAsync($"waiting_list:{request.MapId}", session.user_no, session.rating); await db.StringSetAsync($"waiting:{session.user_no}", 0, startplay_polling_period); // 조건에 만족하는 유저가 없다면 대기 (redis puh로 활성화) var queue = Cache.Instance.GetSubscriber().Subscribe($"sub_user:{session.user_no}"); var cts = new CancellationTokenSource(); cts.CancelAfter((int)startplay_polling_period.TotalMilliseconds); try { var ret = await queue.ReadAsync(cts.Token); StartPlayReply reply = JsonParser.Default.Parse <StartPlayReply>(ret.Message); try { // 매칭이 성공되었음을 알림 await responseStream.WriteAsync(reply); // 다른 유저로 부터 매칭이 되었음을 받았다 // 매칭 정보를 삭제 await SequentialMatchmaking.RemoveMatchUser(session.user_no, request.MapId); } catch (InvalidOperationException) { Log.Information($"StartPlay restore match user {ret.Message}"); // 전송 실패시 매칭 데이터를 백업 await db.StringSetAsync($"restore_match_user:{session.user_no}", ret.Message, restore_match_user_expire); } } catch (OperationCanceledException) { await SequentialMatchmaking.RemoveMatchUser(session.user_no, request.MapId); // 대기시간 만료 클라이언트에게 타임 아웃 처리를 보낸다. await responseStream.WriteAsync(new StartPlayReply() { Code = ErrorCode.Timeout, IsStart = false }); } }
/// <summary> /// 게임 시작 요청 /// </summary> /// <param name="request"></param> /// <param name="responseStream"></param> /// <param name="context"></param> /// <returns></returns> public override async Task StartPlay(StartPlayRequest request, IServerStreamWriter <StartPlayReply> responseStream, ServerCallContext context) { try { //await SequentialMatchmaking.StartPlay(request, responseStream, context); await RankMatchmaking.StartPlay(request, responseStream, context); } catch (Exception ex) { Log.Error($"StartPlay error {ex.ToString()}"); var reply = new StartPlayReply(); reply.Code = ErrorCode.NotEnough; reply.IsStart = false; reply.CharacterList.Add(new StartPlayCharacterInfo()); // 자신포함으로 빈슬롯 한개 넣어줌 await responseStream.WriteAsync(reply); } }
public static async Task StartPlaySimulate(StartPlayRequest request, IServerStreamWriter <StartPlayReply> responseStream, ServerCallContext context, Session session, JMapData map_data, JGameModeData game_mode) { (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; } long match_id = await MatchInstanceId.GetMatchInstanceId(); var matchResult = new MatchResult(match_id, request.MapId); if (await matchResult.AddPlayer(session, map_data, game_mode) == false) { await responseStream.WriteAsync(new StartPlayReply() { Code = ErrorCode.NotEnough }); return; } if (ServerConfiguration.Instance.gameSetting.EnableAIMatch) { matchResult.AddAI(session, map_data, game_mode); } await matchResult.Finish(worldId, server_addr, channel_id, game_mode); await responseStream.WriteAsync(matchResult.replyToClient); await PubStartPlay(matchResult.replyToBattleServer); _ = GameResult.WaitGameResult(session, channel_id, map_data, game_mode).ConfigureAwait(false); }
void Awake() { Joystick = transform.Find("Joystick").GetComponent <ETCJoystick>(); showTimerRequest = GetComponent <ShowTimerRequest>(); startPlayRequest = GetComponent <StartPlayRequest>(); gameOverRequest = GetComponent <GameOverRequest>(); quitBattleRequest = GetComponent <QuitBattleRequest>(); quitGameRequest = GetComponent <QuitGameRequest>(); destroyRequest = GetComponent <DestroyRequest>(); gameChatRequest = GetComponent <GameChatRequest>(); knapsack = transform.Find("KnapsackPanel").GetComponent <Knapsack>(); for (int i = 0; i < 3; i++) { skillPos.Add(transform.Find("Skill" + i)); } roleSelectPanel = transform.Find("RoleSelectPanel"); timer = transform.Find("TimerPanel/Time").GetComponent <Text>(); gameOverText = transform.Find("GameOverPanel/GameOver").GetComponent <Text>(); closeButton = transform.Find("GameOverPanel/CloseButton").GetComponent <Button>(); closeButton.onClick.AddListener(OnCloseClick); EffectDict = facade.GetEffectDict(); SkillItemDict = facade.GetSkillItemDict(); transform.Find("SettingPanel/QuitGameButton").GetComponent <Button>().onClick.AddListener(OnQuitGameClick); chatDialog = transform.Find("ChatDialog"); sendButton = transform.Find("ChatDialog/InputPanel/SendButton"); chatButton = transform.Find("ChatDialog/ChatButton").GetComponent <Button>(); inputField = transform.Find("ChatDialog/InputPanel/InputField").GetComponent <InputField>(); sendButton.GetComponent <Button>().onClick.AddListener(OnSendClick); chatButton.onClick.AddListener(OnChatClick); inputField.onEndEdit.AddListener(x => OnSendClick()); OtherPlayerChatMsgItem = Resources.Load <GameObject>("UIItem/Chat/OtherPlayerChatMsgItem"); LocalPlayerChatMsgItem = Resources.Load <GameObject>("UIItem/Chat/LocalPlayerChatMsgItem"); ChangeSeatItem = Resources.Load <GameObject>("UIItem/ChangeSeatItem"); }
public override async Task StartPlay(StartPlayRequest request, IServerStreamWriter <StartPlayReply> responseStream, ServerCallContext context) { Log.Information("StartPlay {0}", context.Peer); var session = await Session.GetSession(request.SessionId); if (session == null) { Log.Warning("lost session"); await responseStream.WriteAsync(new StartPlayReply() { Code = ErrorCode.LostSession }); return; } var db = Cache.Instance.GetDatabase(); // 다른 유저가 매칭 시도를 했을 경우 var value = await db.StringGetAsync(string.Format("match_user:{0}", session.user_no)); if (value.HasValue) { // 매칭 시도가 성공했을 경우 var ch = await GetChannel((long)value); if (ch != null) { await RemoveMatchUser(session.user_no); Log.Information(string.Format("StartPlay {0}", session.user_no)); await responseStream.WriteAsync(new StartPlayReply() { Code = ErrorCode.Success, IsStart = true, BattleServerAddr = ch.server_addr, WorldId = ch.world_id, }); return; } else { //db.KeyDelete(string.Format("match_user:{0}", session.user_no)); await responseStream.WriteAsync(new StartPlayReply() { Code = ErrorCode.BusyServer, }); return; } } long match_id = 0; var player_list = new List <long>(); var waiting_list = await db.SortedSetRangeByScoreAsync("waiting_list"); 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 {0}", user_no); // 자신은 스킵 if (user_no == session.user_no) { continue; } if ((await db.StringGetAsync(string.Format("waiting:{0}", user_no))).HasValue) { // 매칭에 필요한 유저를 선점한다 if (await db.StringSetAsync(string.Format("match_user:{0}", user_no), match_id, match_user_expire, When.NotExists) == true) { player_list.Add(user_no); Log.Information(string.Format("Candidate User {0}", user_no)); if (player_list.Count == MAX_START_PLAYER_COUNT - 1) { break; } } else { Log.Information("already other match assign user {0}", user_no); } } else { Log.Information("wait timeout user {0}", user_no); // 유효하지 않는 유저는 대기자 목록에서 삭제한다. await RemoveMatchUser(user_no); } } } Log.Information("StartPlay player_list {0}", player_list); if (player_list.Count == MAX_START_PLAYER_COUNT - 1) { // 매칭에 필요한 인원을 모두 찾았을때 // 전투 가능한 서버를 찾아 세팅 (bool ret, string server_addr, byte worldId, string channel_key) = await GetAvailableServer(); if (ret) { var reply = new StartPlayReply() { Code = ErrorCode.Success, IsStart = true, BattleServerAddr = server_addr, WorldId = worldId, }; // 매칭된 유저들에게 알림 for (int i = 0; i < player_list.Count; ++i) { await Cache.Instance.GetSubscriber().PublishAsync(string.Format("sub_user:{0}", player_list[i]), json_formatter.Format(reply)); } await db.StringSetAsync(string.Format("match:{0}", match_id), channel_key, match_expire); await RemoveMatchUser(session.user_no); Log.Information(string.Format("StartPlay {0}", session.user_no)); await responseStream.WriteAsync(reply); return; } else { // 전투 가능한 서버가 없다 Log.Information(string.Format("Cannot find Server user_no:{0}", session.user_no)); await responseStream.WriteAsync(new StartPlayReply() { Code = ErrorCode.BusyServer, }); return; } } // 매칭 시도를 실패하면 선점한 유저를 삭제 await db.KeyDeleteAsync(player_list.Select(key => (RedisKey)string.Format("match_user:{0}", key)).ToArray()); Log.Information("StartPlay waiting... {0}", session.user_no); // 대기자로 등록 await db.SortedSetAddAsync("waiting_list", session.user_no, session.rating); await db.StringSetAsync(string.Format("waiting:{0}", session.user_no), 0, startplay_polling_period); // 조건에 만족하는 유저가 없다면 대기 (redis puh로 활성화) var queue = Cache.Instance.GetSubscriber().Subscribe(string.Format("sub_user:{0}", session.user_no)); var cts = new CancellationTokenSource(); cts.CancelAfter((int)startplay_polling_period.TotalMilliseconds); try { var ret = await queue.ReadAsync(cts.Token); // 다른 유저로 부터 매칭이 되었음을 받았다 // 매칭 정보를 삭제 await RemoveMatchUser(session.user_no); // 매칭이 성공되었음을 알림 StartPlayReply reply = JsonParser.Default.Parse <StartPlayReply>(ret.Message); await responseStream.WriteAsync(reply); } catch (OperationCanceledException) { // 대기시간 만료 클라이언트에게 타임 아웃 처리를 보낸다. await responseStream.WriteAsync(new StartPlayReply() { Code = ErrorCode.Timeout, IsStart = false }); } }
public bool IsChangeRequest(StartPlayRequest request) { return(character_type != (byte)request.SelectedCharacter || map_id != request.MapId); }
/// <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); }
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="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); }
public static async Task StartPlay(StartPlayRequest request, IServerStreamWriter <StartPlayReply> responseStream, ServerCallContext context) { var mapData = ACDC.MapData[request.MapId]; if (mapData == null) { Log.Warning($"StartPlay error map id {request.MapId}"); await responseStream.WriteAsync(new StartPlayReply() { Code = ErrorCode.WrongParam }); return; } var gameModeData = ACDC.GameModeData[mapData.GameMode]; if (gameModeData == null) { Log.Warning($"StartPlay error mode {mapData.GameMode}"); await responseStream.WriteAsync(new StartPlayReply() { Code = ErrorCode.WrongParam }); return; } MinimumStartPlay minimumStartPlay; minimumStartPlayMap.TryGetValue(request.MapId, out minimumStartPlay); var session = await context.GetSession(); if (session == null) { await responseStream.WriteAsync(new StartPlayReply() { Code = ErrorCode.LostSession }); return; } Log.Information($"StartPlay user_no:{session.user_no}, user_name:{session.user_name}, mapId:{request.MapId}, SelectedCharacter:{request.SelectedCharacter}, IsImmediatelyJoin{request.IsImmediatelyJoin}"); bool checkSelectCharacter = await session.SelectCharacter(request.SelectedCharacter); if (checkSelectCharacter == false) { Log.Warning($"StartPlay error character id {request.SelectedCharacter}"); await responseStream.WriteAsync(new StartPlayReply() { Code = ErrorCode.WrongParam }); return; } bool IsAISwitch = false; bool IsFirstRequest = false; bool IsWaitingUser = await WaitingList.IsWaitingUser(session.user_no); bool IsMatchTimeout = false; // 이미 대기중이 였지만 요청이 달라진 경우, 최초 요청으로 판단 if (IsWaitingUser == false || session.IsChangeRequest(request)) { IsFirstRequest = true; History.Info(session.member_no, session.user_no, session.character_no, HistoryLogAction.TryStartPlay, (byte)HistoryLogReason.None, request.SelectedCharacter, request.MapId, "", ""); _ = LogProxy.writeActionLog(session, "플레이", "매칭시도", request.MapId.ToString()).ConfigureAwait(false); } else { if (DateTime.UtcNow > session.first_request_time.AddMilliseconds(ServerConfiguration.Instance.gameSetting.AIMatchTime)) { IsMatchTimeout = true; if (ServerConfiguration.Instance.gameSetting.EnableAIMatch == true) { IsAISwitch = true; } } if (minimumStartPlay != null && minimumStartPlay.Enable && DateTime.UtcNow > session.first_request_time.AddSeconds(minimumStartPlay.Timeout)) { Log.Information($"matchTimeout first_request_time:{session.first_request_time}, now:{DateTime.UtcNow}, timeout:{session.first_request_time.AddSeconds(minimumStartPlay.Timeout)}"); IsMatchTimeout = true; } } Log.Information($"flag IsAISwitch:{IsAISwitch}, IsFirstRequest:{IsFirstRequest}, IsWaitingUser{IsWaitingUser}, IsMatchTimeout{IsMatchTimeout}"); if (request.SelectedCharacter != session.character_type || request.MapId != session.map_id) { var user = await UserCache.GetUser(session.member_no, session.user_no, false); user.character_no = session.character_no; user.map_id = (byte)request.MapId; user.IsDirty = true; } // 게임 시작 요청 정보를 캐싱 await session.UpdateSessionLock(request.SelectedCharacter, request.MapId, IsFirstRequest); if (request.IsImmediatelyJoin) { await StartPlaySimulate(request, responseStream, context, session, mapData, gameModeData); return; } long match_id = await MatchInstanceId.GetMatchInstanceId(); if ((await MatchUser.OccupyMatchUser(session.user_no, match_id)) == false) { // 다른 플레이어로 인해 매칭이 완료 되었는지 확인 if ((await RestoreMatchUser(session, responseStream)) == true) { if (ServerConfiguration.Instance.gameSetting.EnableReJoin == false) { // 재입장이 불가하면, 게임 시작 직후 매칭 정보 삭제 await MatchUser.RemoveMatchUser(session.user_no); } return; } else { await responseStream.WriteAsync(new StartPlayReply() { Code = ErrorCode.NotEnough, IsStart = false, BattleServerAddr = "", WorldId = 0, MapId = request.MapId, }); return; } } if (request.IsCancel) { // 대기 목록에서 제거 await WaitingList.RemoveWaitingUser(session.user_no); await MatchUser.RemoveMatchUser(session.user_no); await responseStream.WriteAsync(new StartPlayReply() { Code = ErrorCode.NotEnough, IsStart = false, BattleServerAddr = "", WorldId = 0, MapId = request.MapId, }); return; } // 대기중이 플레이어 찾기 (var matchResult, var search_success) = await SearchPlayer(session, match_id, mapData, gameModeData); if (search_success == false && IsAISwitch == true) { // 부족한 인원 만큼 AI로 채워 넣는다.(자신은 제외) int cnt = (GetStartPlayerCount(gameModeData) - 1) - matchResult.replyToClient.CharacterList.Count; for (int i = 0; i < cnt; ++i) { matchResult.AddAI(session, mapData, gameModeData); } } if (search_success == true || IsAISwitch == true || (ServerConfiguration.Instance.gameSetting.MatchForce && IsMatchTimeout) || (minimumStartPlay != null && minimumStartPlay.Enable && IsMatchTimeout && matchResult.replyToClient.CharacterList.Count + 1 >= minimumStartPlay.PlayerCount) ) { // 게임 시작 if ((await StartPlay(match_id, session, request, responseStream, matchResult, mapData, gameModeData)) == false) { // 예약했던 플레이어 취소 await MatchUser.CancelOccupiedMatchUser(matchResult.replyToBattleServer.players); } else { if (ServerConfiguration.Instance.gameSetting.EnableReJoin == false) { // 재입장이 불가하면, 게임 시작 직후 매칭 정보 삭제 await MatchUser.RemoveMatchUser(session.user_no); } } return; } // 예약했던 플레이어 취소 await MatchUser.CancelOccupiedMatchUser(matchResult.replyToBattleServer.players); Log.Information("StartPlay waiting... {0}", session.user_no); // 대기 await WaitStartPlay(session, request, responseStream); // 검색 실패시 다음 검색 조건 범위를 넓힌다. await session.WideningRangeRankLock(); // 실패 결과 리턴 matchResult.replyToClient.Code = ErrorCode.NotEnough; matchResult.replyToClient.IsStart = false; matchResult.replyToClient.CharacterList.Add(new StartPlayCharacterInfo()); // 자신포함으로 빈슬롯 한개 넣어줌 await responseStream.WriteAsync(matchResult.replyToClient); }
public static async Task <bool> StartPlay(long match_id, Session session, StartPlayRequest request, IServerStreamWriter <StartPlayReply> responseStream, MatchResult matchResult, JMapData map_data, JGameModeData game_mode) { // 매칭에 필요한 인원을 모두 찾았을때 // 전투 가능한 서버를 찾아 세팅 (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); } if (await matchResult.AddPlayer(session, map_data, game_mode) == false) { Log.Error($"StartPlay error user_no:{session.user_no}"); await responseStream.WriteAsync(new StartPlayReply() { Code = ErrorCode.NotEnough }); return(false); } await matchResult.Finish(worldId, server_addr, channel_id, game_mode); // 매칭된 유저들에게 알림 await Match.SaveMatch(match_id, matchResult.replyToClient); // 대기 목록에서 삭제 foreach (var p in matchResult.replyToBattleServer.players.Values) { await WaitingList.RemoveWaitingUser(p.user_no); } // 배틀서버에 알림 await PubStartPlay(matchResult.replyToBattleServer); Log.Information($"StartPlay {session.user_no}, channel_msg:{channel_key}"); // 게임 시작 요청에 대한 응답 전송 await responseStream.WriteAsync(matchResult.replyToClient); // 매칭이 성공적으로 이루어졌으므로 이후 매칭 결과를 pub/sub으로 전달 받는다. _ = GameResult.WaitGameResult(session, channel_id, map_data, game_mode).ConfigureAwait(false); History.Info(session.member_no, session.user_no, session.character_no, HistoryLogAction.StartPlay, (byte)HistoryLogReason.None, matchResult.replyToBattleServer.players.Count, matchResult.replyToClient.MapId, match_id.ToString(), session.character_type.ToString()); _ = LogProxy.writeActionLog(session, "플레이", "매칭성공", matchResult.replyToClient.MapId.ToString()).ConfigureAwait(false); var characterNames = new List <string>(); var characterLevels = new List <int>(); foreach (var player in matchResult.replyToBattleServer.players) { characterNames.Add(player.Value.user_id); characterLevels.Add(player.Value.character_level); } _ = LogProxy.writeRoundLog(session, game_mode.Name, "", "", "10", 0, 0, 0, characterNames, characterLevels, "").ConfigureAwait(false); return(true); }