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 }); }
public void Init(int map_id, long match_id, int player_count) { // 이전에 등록했던 시작 이벤트 초기화 OnStart = null; // 게임 시작 이벤트 등록 foreach (var gameObject in World.Instance(WorldId).GetGameObjects()) { if (gameObject.GetClassId() == (byte)GameObjectClassId.Trap) { RegisterStartEvent(((Trap)gameObject).OnStart); } else if (gameObject.GetClassId() == (byte)GameObjectClassId.TreasureBox) { RegisterStartEvent(((TreasureBox)gameObject).OnStart); } else if (gameObject.GetClassId() == (byte)GameObjectClassId.Train) { RegisterStartEvent(((Train)gameObject).OnStart); } } mMapData = ACDC.MapData[map_id]; mGameModeData = ACDC.GameModeData[mMapData.GameMode]; game_mode = CreateGameMode((GameModeType)mGameModeData.ID); mMatchId = match_id; StartTime = Timing.sInstance.GetFrameStartTime(); state = GameModeState.Init; InitTime = Timing.sInstance.GetFrameStartTime(); ReservedPlayerCount = player_count; }
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); }
/// <summary> /// 게임 결과 기다림 /// </summary> /// <param name="session"></param> /// <param name="request"></param> /// <param name="responseStream"></param> /// <returns></returns> public static async Task WaitGameResult(Session session, string channel_id, JMapData map_data, JGameModeData game_mode) { string key = $"game_result:{channel_id}"; Log.Information($"WaitGameResult {key}"); Interlocked.Increment(ref RankMatchmaking.MatchCount); var queue = Cache.Instance.GetSubscriber().Subscribe(key); var cts = new CancellationTokenSource(); cts.CancelAfter((int)game_result_expire.TotalMilliseconds); try { var ret = await queue.ReadAsync(cts.Token); Interlocked.Decrement(ref RankMatchmaking.MatchCount); ServerCommon.GameResult reply = JsonConvert.DeserializeObject <ServerCommon.GameResult>(ret.Message); Log.Information($"game result {ret.Message.ToString()}"); int total_win_medal = 0; int total_lose_medal = 0; int total_draw_medal = 0; int total_mvp_medal = 0; int total_rankup_medal = 0; await Match.RemoveMatch(reply.match_id); var characterNames = new List <string>(); var characterLevels = new List <int>(); foreach (var player in reply.player_result) { if (player.Value.IsLeave) { continue; } var last_session = await Session.GetSession(player.Key, false); if (last_session != null) { bool is_changed_character_rank_level = false; await using (var mylock = await RedLock.CreateLockAsync($"lock:session:{last_session.session_id}")) { await using (var user = await UserCache.GetUser(last_session.member_no, last_session.user_no, true, true, true)) await using (var character = await CharacterCache.Instance.GetEntity(last_session.member_no, last_session.character_no, true, true, true)) { user.play_point += player.Value.play_point; var last_account_battle_score = user.battle_score; UserGrowth.IncreaseBattleScore(user, player.Value.battle_point); var last_battle_score = character.battle_score; var last_rank_level = character.rank_level; CharacterGrowth.IncreaseBattleScore(character, player.Value.battle_point); var(abs, cbs, wc) = await Ranking.Update(last_session, reply.season_no, player.Value.battle_point, player.Value.IsWin); bool is_character_rank_level_up = false; if (last_rank_level != character.rank_level) { if (last_rank_level < character.rank_level) { is_character_rank_level_up = true; } } if (last_battle_score != character.battle_score) { var rankData = ACDC.RankData.GetRank(character.battle_score); if (rankData != null) { if (last_session.rank != rankData.Rank) { is_changed_character_rank_level = true; last_session.rank = rankData.Rank; } } } var last_medal = user.medal; var medal_count = Medal.CalcMedal(user, last_session, reply.is_draw, player.Value, is_character_rank_level_up, game_mode, ref total_win_medal, ref total_lose_medal, ref total_draw_medal, ref total_mvp_medal, ref total_rankup_medal); await Inventory.Insert(last_session, user, character, (int)GameItemId.Medal, medal_count, null); // 배틀에서 넘어온 미션 데이터가 없는 경우 초기화 if (player.Value.missions == null) { player.Value.missions = new Dictionary <int, int>(); } player.Value.missions.Increment((int)MissionType.Mission_GetMedal, medal_count); await MissionManager.Progress(last_session, player.Value.missions); History.Info(last_session.member_no, last_session.user_no, last_session.character_no, HistoryLogAction.GainAccountBattleScore, (byte)HistoryLogReason.GameResultReward, (int)user.battle_score, (int)last_account_battle_score, reply.match_id.ToString(), ""); History.Info(last_session.member_no, last_session.user_no, last_session.character_no, HistoryLogAction.GainCharacterBattleScore, (byte)HistoryLogReason.GameResultReward, (int)character.battle_score, (int)last_battle_score, reply.match_id.ToString(), ""); characterNames.Add(last_session.user_name); characterLevels.Add(character.rank_level); } } //Log.Information($"session:{last_session.session_id}, rank:{last_session.rank}"); if (is_changed_character_rank_level) { await Session.UpdateSessionLock(last_session.session_id, delegate(Session s) { s.rank = last_session.rank; }); } // 게임 종료 이후 매칭 정보 삭제 await MatchUser.RemoveMatchUser(last_session.user_no); } else { Log.Warning($"game result lost session:{player.Key}, msg:{ret.Message}"); } } MatchLog.Info(reply, total_win_medal, total_lose_medal, total_draw_medal, total_mvp_medal, total_rankup_medal); string resultTp; if (reply.is_draw) { resultTp = "26"; _ = LogProxy.writeActionLog(session, "플레이", "무승부", map_data.ID.ToString()).ConfigureAwait(false); } else if (reply.statistics.clear == 1) { resultTp = "21"; _ = LogProxy.writeActionLog(session, "플레이", "클리어", map_data.ID.ToString()).ConfigureAwait(false); } else { resultTp = "22"; } _ = LogProxy.writeRoundLog(session, game_mode.Name, "", "", resultTp, 0, reply.statistics.start_time, reply.statistics.end_time, characterNames, characterLevels, "").ConfigureAwait(false); if (reply.statistics.leave_player > 0) { _ = LogProxy.writeActionLog(session, "플레이", "이탈", map_data.ID.ToString(), reply.statistics.leave_player.ToString()).ConfigureAwait(false); } if (reply.statistics.normal_item > 0) { _ = LogProxy.writeActionLog(session, "플레이", "일반아이템획득", map_data.ID.ToString(), reply.statistics.normal_item.ToString()).ConfigureAwait(false); } if (reply.statistics.tactic_item > 0) { _ = LogProxy.writeActionLog(session, "플레이", "전략아이템획득", map_data.ID.ToString(), reply.statistics.tactic_item.ToString()).ConfigureAwait(false); } } catch (OperationCanceledException ex) { Log.Information($"game result timeout {ex.ToString()}"); } }
public static async Task <(MatchResult, bool)> SearchPlayer(Session session, long match_id, JMapData map_data, JGameModeData game_mode) { bool result = false; var matchResult = new MatchResult(match_id, session.map_id); if (GetStartPlayerCount(game_mode) <= 1) { return(matchResult, true); } Session other_session = null; var seq = new RankSequencer() { rank = session.rank, min_rank = session.min_rank, max_rank = session.max_rank }; foreach (var rank in seq) { var users = await WaitingList.GetWaitingUser(session.map_id, rank, defaultGetWaitingUser); for (int i = 0; i < users.Count; ++i) { //Log.Information($"searching... waiting user : {users[i]}, rank : {rank}"); // 자신은 스킵 if (users[i] == session.user_no) { continue; } if ((other_session = await Session.GetSession(users[i], false)) == null // 대기중 유저 세션 만료 ) { Log.Information("cannot find Session {0}", users[i]); await WaitingList.RemoveWaitingUser(users[i]); continue; } if (other_session.rank != rank) { continue; } if (await MatchUser.OccupyMatchUser(users[i], match_id) == false) { continue; } if (await matchResult.AddPlayer(other_session, map_data, game_mode) == false) { Log.Error($"SearchPlayer error user_no:{session.user_no}"); continue; } Log.Information($"Candidate User {other_session.user_no}"); if (matchResult.replyToBattleServer.players.Count == GetStartPlayerCount(game_mode) - 1) { result = true; return(matchResult, result); } } } return(matchResult, result); }
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); }
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); }