using GameServer.Contents.GameMode.Mode_Battle.Manage; using MetaAssets; using Newtonsoft.Json; using ServerBase; using ServerCommon; using ServerCommon.BusinessLogDomain; using ServerCore; namespace GameServer; public partial class BattleInstanceUpdateAction { private async Task battleInstanceStateUpdate(GameModeTPSFreeForAll battleInstanceRoom, BattleInstanceSnapshotAttribute attribute) { var result = new Result(); var round_state = attribute.m_combat_pod_mode.m_round_state_type; switch (round_state) { case BattleRoundStateType.Rounding: //라운드가 끝났을때 Wait 혹은 End 처리 result = await battleInstanceRoundingStateUpdate(battleInstanceRoom, attribute); break; case BattleRoundStateType.RoundWait: //시간 됐을때 Rounding 처리 result = await battleInstanceWaitStateUpdate(battleInstanceRoom, attribute); break; case BattleRoundStateType.RoundEndAll: //시간 지났을때 kick 처리 result = await battleInstanceEndStateUpdate(battleInstanceRoom, attribute); break; case BattleRoundStateType.Destroyed: break; default: Log.getLogger().error($"BattleRoundStateType None error room_id : {battleInstanceRoom.getRoomId()}"); return result; } return result; } private async Task battleInstanceWaitStateUpdate(GameModeTPSFreeForAll battleInstanceRoom, BattleInstanceSnapshotAttribute attribute) { var result = new Result(); await Task.CompletedTask; var now = DateTimeHelper.Current; var state_start_time = attribute.m_combat_pod_mode.m_current_state_start_time; var wait_end_time = state_start_time.AddSeconds(battleInstanceRoom.m_ffa_config_meta.NextRoundWaitTime); //시간이 지났을 경우 state 바꿔주는 처리 필요 if (now < wait_end_time) return result; using (var releaser = await battleInstanceRoom.getAsyncLock()) { attribute.m_combat_pod_mode.m_round_state_type = BattleRoundStateType.Rounding; attribute.m_combat_pod_mode.m_current_state_start_time = wait_end_time; attribute.m_combat_pod_mode.m_current_round += 1; attribute.m_combat_pod_mode.m_charged_step = 0; attribute.m_combat_pod_mode.m_rewarded_step = 0; attribute.m_combat_pod_mode.m_pod_combat.setActive(now); (result, var anchor_guid) = BattleRoomHelper.getRandomCombatPodAnchorGuid(attribute, battleInstanceRoom); if (result.isFail()) { Log.getLogger().Error("get Random pod combat anchor guid faile !!! "); return result; } attribute.m_combat_pod_mode.m_pod_combat.m_source_storage_anchor_guid = anchor_guid; } BattleRoomNotifyHelper.broadcast_GS2C_NTF_BATTLE_INSTANCE_STATE(battleInstanceRoom); BattleRoomNotifyHelper.broadcast_GS2C_NTF_POD_COMBAT_STATE(battleInstanceRoom); battleObjectStateInitAndNotify(battleInstanceRoom, attribute); //로그 추가 var invokers = new List(); var log_action = new LogAction(LogActionType.BattleRoundStateUpdate.ToString()); var room_id = battleInstanceRoom.getRoomId(); var ended_round = attribute.m_combat_pod_mode.m_current_round; var round_state = attribute.m_combat_pod_mode.m_round_state_type; var users = battleInstanceRoom.getInstanceRoom().tryGetInstanceExistUserForLog(); BattleRoundUpdateBusinessLog business_log = new(room_id, ended_round, round_state, users); invokers.Add(business_log); //BusinessLogger.collectLogs(log_action, battleInstanceRoom, invokers); //kihoon todo : 이거 수정해야된다. return result; } private async Task battleInstanceRoundingStateUpdate(GameModeTPSFreeForAll battleInstanceRoom, BattleInstanceSnapshotAttribute attribute) { var result = new Result(); var now = DateTimeHelper.Current; var round_start_time = attribute.m_combat_pod_mode.m_current_state_start_time; var round_end_time = round_start_time.AddSeconds(battleInstanceRoom.m_ffa_config_meta.RoundTime); //라운드에 대한 시간이 지났을 경우 state 바꿔주는 처리 필요 if (round_end_time <= now) { await roundingUpdate(battleInstanceRoom, round_end_time); } else { await podCombatRewardUpdate(battleInstanceRoom, attribute, now); await stepUpdate(battleInstanceRoom, attribute, now); } return result; } private async Task roundingUpdate(GameModeTPSFreeForAll battleInstanceRoom, DateTime roundEndTime) { var result = new Result(); string occupier_guid = string.Empty; using (var releaser = await battleInstanceRoom.getAsyncLock()) { var attribute = battleInstanceRoom.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(attribute, () => $"attribute is null !!! - {battleInstanceRoom.toBasicString()}"); occupier_guid = attribute.m_combat_pod_mode.m_pod_combat.m_current_occupier_guid; Player? rewarded_player = null; if (!occupier_guid.Equals(string.Empty)) { if (false == battleInstanceRoom.getInstanceRoom().tryGetInstanceMember(occupier_guid, out rewarded_player)) { //보상은 안되더라도 라운드는 진행 가능하게 처리해야할듯... var err_msg = $"not exist user in instance_room !!! user_guid : {occupier_guid}"; Log.getLogger().error(err_msg); } } if (rewarded_player is null) { result = await roundingUpdateWithoutReward(battleInstanceRoom, roundEndTime); } else { result = await roundingUpdateWithReward(battleInstanceRoom, roundEndTime, rewarded_player); } if (result.isFail()) { Log.getLogger().error(result.toBasicString()); } } } private async Task roundingUpdateWithReward(GameModeTPSFreeForAll battleInstanceRoom, DateTime roundEndTime, Player player) { var result = new Result(); //bool need_battle_end_result_noti = false; var server_logic = GameServerApp.getServerLogic(); List infos = new(); CommonResult common_result = new(); var fn_battle_round_update = async delegate() { var attribute = battleInstanceRoom.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(attribute, () => $"attribute is null !!! - {battleInstanceRoom.toBasicString()}"); if (battleInstanceRoom.m_round_count <= attribute.m_combat_pod_mode.m_current_round) { attribute.m_combat_pod_mode.m_round_state_type = BattleRoundStateType.RoundEndAll; //배틍 종료에 대한 정보를 알려줄지 말지에 대한 noti //need_battle_end_result_noti = true; } else { attribute.m_combat_pod_mode.m_round_state_type = BattleRoundStateType.RoundWait; } attribute.m_combat_pod_mode.m_current_state_start_time = roundEndTime; (result, var rewards, var reward_start_step, var reward_end_step) = await podCombatUpdateIfHasOccupier(battleInstanceRoom, attribute, player); if (result.isFail()) return result; //모든 픽업포드 비활성화, 모든 스토리지 비활성화 infos.AddRange(battleObjectPickupPodsDeactive(attribute)); infos.AddRange(battleObjectPodStoragesDeactive(attribute)); attribute.m_combat_pod_mode.m_pod_combat.setDeactive(); attribute.modifiedEntityAttribute(true); Log.getLogger().debug($"roundingUpdateWithReward attribute info : {JsonConvert.SerializeObject(attribute)}"); (result, var doc) = await attribute.toDocBase(); if (result.isFail()) return result; //batch 처리 var batch = new QueryBatchEx(player, LogActionType.BattleRoundStateUpdate, server_logic.getDynamoDbClient()); { batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner()); if (doc is not null) { batch.addQuery(new DBQEntityWrite(doc)); } } //로그 추가 var room_id = battleInstanceRoom.getRoomId(); var ended_round = attribute.m_combat_pod_mode.m_current_round; var round_state = attribute.m_combat_pod_mode.m_round_state_type; var users = battleInstanceRoom.getInstanceRoom().tryGetInstanceExistUserForLog(); BattleRoundUpdateBusinessLog business_log = new(room_id, ended_round, round_state, users); batch.appendBusinessLog(business_log); BattlePodCombatRewardBusinessLog combat_business_log = new(room_id, ended_round, round_state , player.getUserGuid(), player.getUserNickname() , reward_start_step, reward_end_step, rewards); batch.appendBusinessLog(combat_business_log); result = await QueryHelper.sendQueryAndBusinessLog(batch); if (result.isFail()) return result; //보상 내용 가져올것 var found_transaction_runner = player.findTransactionRunner(TransactionIdType.PrivateContents); NullReferenceCheckHelper.throwIfNull(found_transaction_runner, () => $"found_transaction_runner is null !!! - {battleInstanceRoom.toBasicString()}"); common_result = found_transaction_runner.getCommonResult(); return result; }; result = await player.runTransactionRunnerSafelyWithTransGuid(player.getUserGuid(), TransactionIdType.PrivateContents, BattleConstant.BATTLE_INSTANCE_TRANSACTION_NAME, fn_battle_round_update); if (result.isFail()) { var err_msg = $"Failed to runTransactionRunnerSafelyWithTransGuid() !!! : {result.toBasicString()}, {battleInstanceRoom.toBasicString()}"; Log.getLogger().error(err_msg); return result; } BattleRoomNotifyHelper.broadcast_GS2C_NTF_BATTLE_INSTANCE_STATE(battleInstanceRoom); BattleRoomNotifyHelper.broadcast_GS2C_NTF_BATTLE_OBJECT_STATE_INFO(battleInstanceRoom, infos); BattleRoomNotifyHelper.broadcast_GS2C_NTF_POD_COMBAT_STATE(battleInstanceRoom); BattleRoomNotifyHelper.broadcast_GS2C_NTF_BATTLE_REWARD(battleInstanceRoom, player.getUserGuid(), common_result); return result; } private async Task roundingUpdateWithoutReward(GameModeTPSFreeForAll battleInstanceRoom, DateTime roundEndTime) { var result = new Result(); bool need_battle_end_result_noti = false; var server_logic = GameServerApp.getServerLogic(); List infos = new(); var fn_battle_round_update = async delegate() { var attribute = battleInstanceRoom.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(attribute, () => $"attribute is null !!! - {battleInstanceRoom.toBasicString()}"); if (battleInstanceRoom.m_round_count <= attribute.m_combat_pod_mode.m_current_round) { attribute.m_combat_pod_mode.m_round_state_type = BattleRoundStateType.RoundEndAll; //배틍 종료에 대한 정보를 알려줄지 말지에 대한 noti need_battle_end_result_noti = true; } else { attribute.m_combat_pod_mode.m_round_state_type = BattleRoundStateType.RoundWait; } attribute.m_combat_pod_mode.m_current_state_start_time = roundEndTime; //모든 픽업포드 비활성화, 모든 스토리지 비활성화 infos.AddRange(battleObjectPickupPodsDeactive(attribute)); infos.AddRange(battleObjectPodStoragesDeactive(attribute)); attribute.m_combat_pod_mode.m_pod_combat.setDeactive(); attribute.modifiedEntityAttribute(true); //batch 처리 // var batch = new QueryBatch(battleInstanceRoom, LogActionType.BattleRoundStateUpdate, server_logic.getDynamoDbClient()); // { // batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner()); // } //로그 추가 var room_id = battleInstanceRoom.getRoomId(); var ended_round = attribute.m_combat_pod_mode.m_current_round; var round_state = attribute.m_combat_pod_mode.m_round_state_type; var users = battleInstanceRoom.getInstanceRoom().tryGetInstanceExistUserForLog(); BattleRoundUpdateBusinessLog business_log = new(room_id, ended_round, round_state, users); //batch.appendBusinessLog(business_log); //kihoon todo : 로그랑 배치 수정해서 올려야 된다. //result = await QueryHelper.sendQueryAndBusinessLog(batch); await Task.CompletedTask; if (result.isFail()) return result; return result; }; result = await battleInstanceRoom.runTransactionRunnerSafelyWithTransGuid(battleInstanceRoom.getRoomId(), TransactionIdType.PrivateContents, BattleConstant.BATTLE_INSTANCE_TRANSACTION_NAME, fn_battle_round_update); if (result.isFail()) { var err_msg = $"Failed to runTransactionRunnerSafelyWithTransGuid() !!! : {result.toBasicString()}, {battleInstanceRoom.toBasicString()}"; Log.getLogger().error(err_msg); return result; } BattleRoomNotifyHelper.broadcast_GS2C_NTF_BATTLE_INSTANCE_STATE(battleInstanceRoom); BattleRoomNotifyHelper.broadcast_GS2C_NTF_BATTLE_OBJECT_STATE_INFO(battleInstanceRoom, infos); BattleRoomNotifyHelper.broadcast_GS2C_NTF_POD_COMBAT_STATE(battleInstanceRoom); if (need_battle_end_result_noti) { } return result; } private async Task stepUpdate(GameModeTPSFreeForAll battleInstanceRoom, BattleInstanceSnapshotAttribute attribute, DateTime now) { var max_charge_level = battleInstanceRoom.m_ffa_reward_meta .Where(kvp => kvp.Key == battleInstanceRoom.m_ffa_reward_meta.Keys.Max()) .Select(kvp => kvp.Key) .FirstOrDefault(); //최대 스텝이면 알려줄것 없다. if (max_charge_level <= attribute.m_combat_pod_mode.m_charged_step) return; //시간이 아직 안지났을 경우는 m_charged_step 시간을 체크 해줘야 된다... var round_start_time = attribute.m_combat_pod_mode.m_current_state_start_time; var current_charge_level = attribute.m_combat_pod_mode.m_charged_step; var next_charge_level = current_charge_level + 1; //다음 충전까지 필요한 시간의 합 var next_charge_time_total = battleInstanceRoom.m_ffa_reward_meta .Where(kvp => kvp.Key <= next_charge_level) .Sum(kvp => kvp.Value.ChargeTime); //여기도 using만 사용 로그만 남길것... using (var releaser = await battleInstanceRoom.getAsyncLock()) { var next_step_active_time = round_start_time.AddSeconds(next_charge_time_total); if (next_step_active_time <= now) { attribute.m_combat_pod_mode.m_charged_step = next_charge_level; BattleRoomNotifyHelper.broadcast_GS2C_NTF_BATTLE_INSTANCE_STATE(battleInstanceRoom); } } } private async Task podCombatRewardUpdate(GameModeTPSFreeForAll battleInstanceRoom, BattleInstanceSnapshotAttribute attribute, DateTime now) { var occupier_guid = string.Empty; CommonResult common_result = new(); bool need_pod_combat_noti = false; using (var releaser = await battleInstanceRoom.getAsyncLock()) { occupier_guid = attribute.m_combat_pod_mode.m_pod_combat.m_current_occupier_guid; if (occupier_guid.Equals(string.Empty)) return; if (false == battleInstanceRoom.getInstanceRoom().tryGetInstanceMember(occupier_guid, out var player)) { Log.getLogger().error($"Not Exist Player in battle instance room occupier_guid : {occupier_guid}"); return; } var charged_step = attribute.m_combat_pod_mode.m_charged_step; var rewarded_step = attribute.m_combat_pod_mode.m_rewarded_step; if (charged_step <= rewarded_step) return; var accupied_time = attribute.m_combat_pod_mode.m_pod_combat.m_occupied_time; var rewadable_time = accupied_time.AddSeconds(battleInstanceRoom.m_ffa_config_meta.GetRewardTime); if (rewadable_time > now) return; var result = new Result(); var fn_pod_combat_reward_update = async delegate() { //여기서 보상처리 가능하다. var rewards = makePodCombatOccupyReward(rewarded_step, charged_step, battleInstanceRoom); result = await addPodCommbatOccupyReward(player, battleInstanceRoom, rewards); if (result.isFail()) { string err_msg = $"addPodCommbatOccupyReward return fail.. error : {result.toBasicString()}"; Log.getLogger().error(err_msg); return result; } attribute.m_combat_pod_mode.m_rewarded_step = charged_step; attribute.m_combat_pod_mode.m_pod_combat.m_occupied_time = rewadable_time; var max_charge_level = battleInstanceRoom.m_ffa_reward_meta .Where(kvp => kvp.Key == battleInstanceRoom.m_ffa_reward_meta.Keys.Max()) .Select(kvp => kvp.Key) .FirstOrDefault(); if (max_charge_level <= charged_step) { attribute.m_combat_pod_mode.m_pod_combat.setDeactive(); need_pod_combat_noti = true; } attribute.modifiedEntityAttribute(true); (result, var doc) = await attribute.toDocBase(); if (result.isFail()) { Log.getLogger().error(result.toBasicString()); } var server_logic = GameServerApp.getServerLogic(); //batch 처리 var batch = new QueryBatchEx(player, LogActionType.BattlePodCombatOccupyReward, server_logic.getDynamoDbClient()); { batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner()); if (doc is not null) { batch.addQuery(new DBQEntityWrite(doc)); } } BattleObjectLogInfo info = new(); info.m_battle_object_type = EBattleObjectType.Pod_Combat; List log_infos = new(); var room_id = battleInstanceRoom.getRoomId(); var current_round = attribute.m_combat_pod_mode.m_current_round; var round_state_type = attribute.m_combat_pod_mode.m_round_state_type; var business_log = new BattlePodCombatRewardBusinessLog(room_id, current_round, round_state_type , player.getUserGuid(), player.getUserNickname(), charged_step, rewarded_step, rewards); batch.appendBusinessLog(business_log); result = await QueryHelper.sendQueryAndBusinessLog(batch); if (result.isFail()) return result; //보상 내용 가져올것 var found_transaction_runner = player.findTransactionRunner(TransactionIdType.PrivateContents); NullReferenceCheckHelper.throwIfNull(found_transaction_runner, () => $"found_transaction_runner is null !!! - {player.toBasicString()}"); common_result = found_transaction_runner.getCommonResult(); return result; }; result = await player.runTransactionRunnerSafelyWithTransGuid(player.getUserGuid(), TransactionIdType.PrivateContents, BattleConstant.BATTLE_INSTANCE_TRANSACTION_NAME, fn_pod_combat_reward_update); if (result.isFail()) { var err_msg = $"Failed to runTransactionRunnerSafelyWithTransGuid() !!! : {result.toBasicString()}, {battleInstanceRoom.toBasicString()}"; Log.getLogger().error(err_msg); return; } } BattleRoomNotifyHelper.broadcast_GS2C_NTF_BATTLE_INSTANCE_STATE(battleInstanceRoom); BattleRoomNotifyHelper.broadcast_GS2C_NTF_BATTLE_REWARD(battleInstanceRoom, occupier_guid, common_result); if (need_pod_combat_noti) { BattleRoomNotifyHelper.broadcast_GS2C_NTF_POD_COMBAT_STATE(battleInstanceRoom); } } private async Task battleInstanceEndStateUpdate(GameModeTPSFreeForAll battleInstanceRoom, BattleInstanceSnapshotAttribute attribute) { var result = new Result(); await Task.CompletedTask; var all_round_end_time = attribute.m_combat_pod_mode.m_current_state_start_time; var end_time = all_round_end_time.AddSeconds(battleInstanceRoom.m_ffa_config_meta.ResultUIWaitTime); var now = DateTimeHelper.Current; if (now < end_time) return result; using (var releaser = await battleInstanceRoom.getAsyncLock()) { attribute.m_combat_pod_mode.m_round_state_type = BattleRoundStateType.Destroyed; attribute.m_combat_pod_mode.m_current_state_start_time = end_time; } var users = battleInstanceRoom.getInstanceRoom().tryGetInstanceExistUserForLog(); //여기서 배틀 인스턴스가 완전히 shutdown 됐다는 Noti 전달 BattleRoomNotifyHelper.broadcast_GS2C_NTF_BATTLE_INSTANCE_STATE(battleInstanceRoom); //log 추가 var invokers = new List(); var log_action = new LogAction(LogActionType.BattleRoundStateUpdate.ToString()); var room_id = battleInstanceRoom.getRoomId(); var ended_round = attribute.m_combat_pod_mode.m_current_round; var round_state = attribute.m_combat_pod_mode.m_round_state_type; BattleRoundUpdateBusinessLog business_log = new(room_id, ended_round, round_state, users); invokers.Add(business_log); //BusinessLogger.collectLogs(log_action, battleInstanceRoom, invokers);// kihoon todo : 이거 수정해야된다. return result; } }