using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; using ServerCore; using ServerBase; using ServerCommon; namespace GameServer; public class NormalQuestCheckTicker : EntityTicker { public NormalQuestCheckTicker(double onTickIntervalMilliseconds, CancellationTokenSource? cts) : base(EntityType.NormalQuestCheckTicker, onTickIntervalMilliseconds, cts) { } public async Task onTaskTick_old() { Stopwatch? stopwatch = null; var event_tid = string.Empty; var server_logic = GameServerApp.getServerLogic(); ArgumentNullException.ThrowIfNull(server_logic); var server_config = server_logic.getServerConfig(); ArgumentNullException.ThrowIfNull(server_config); if (true == server_config.PerformanceCheckEnable) { event_tid = System.Guid.NewGuid().ToString("N"); stopwatch = Stopwatch.StartNew(); } //여기에 Transaction 걸기 await QuestManager.It.questTimerEventCheck(); await QuestManager.It.questNormalActiveCheck(); if (null != stopwatch) { var elapsed_msec = stopwatch.ElapsedMilliseconds; stopwatch.Stop(); Log.getLogger().debug($"{GetType()} Ticker Stopwatch Stop : ETID:{event_tid}, ElapsedMSec:{elapsed_msec}, TickIntervalMSec:{getOnTickIntervalMilliseconds()}"); } } public override async Task onTaskTick() { Stopwatch? stopwatch = null; var event_tid = string.Empty; var server_logic = GameServerApp.getServerLogic(); ArgumentNullException.ThrowIfNull(server_logic); var server_config = server_logic.getServerConfig(); ArgumentNullException.ThrowIfNull(server_config); if (true == server_config.PerformanceCheckEnable) { event_tid = System.Guid.NewGuid().ToString("N"); stopwatch = Stopwatch.StartNew(); } //await QuestManager.It.questTimerEventCheck(); 의 대안 var timer_check_user = QuestManager.It.getTimerCheckUser(); List delete_checker = new(); ArgumentNullException.ThrowIfNull(timer_check_user, $"timer_check_user is null !!!"); var player_manager = server_logic.getPlayerManager(); ArgumentNullException.ThrowIfNull(player_manager, $"player_manager is null !!!"); foreach (string user_guid in timer_check_user) { if (false == player_manager.tryGetUserByPrimaryKey(user_guid, out var player)) { delete_checker.Add(user_guid); continue; } var user_create_or_load_action = player.getEntityAction(); ArgumentNullException.ThrowIfNull(user_create_or_load_action, $"user_create_or_load_action is null !!! - {player.toBasicString()}"); if (false == user_create_or_load_action.isCompletedLoadUser()) { continue; } var fn_transaction_runner = async delegate() { var result = await QuestManager.It.QuestCheckWithoutTransaction(player, new QuestTimer(EQuestEventTargetType.TIMER, EQuestEventNameType.ENDED)); ArgumentNullException.ThrowIfNull(result, $"result is null !!!"); var batch = new QueryBatchEx(player, LogActionType.QuestTaskUpdate, server_logic.getDynamoDbClient()); { batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner()); } result = await QueryHelper.sendQueryAndBusinessLog(batch); if (result.isFail()) { var err_msg = $"Failed to sendQueryAndBusinessLog() !!! : {result.toBasicString()} - {player.toBasicString()}"; Log.getLogger().error(err_msg); return result; } return result; }; var result = await player.runTransactionRunnerSafelyWithTransGuid(player.getUserGuid(), TransactionIdType.PrivateContents, "QuestTimerCheckTick", fn_transaction_runner); if (result.isFail()) { var err_msg = $"Failed to runTransactionRunnerSafelyWithTransGuid() !!! : {result.toBasicString()} - {player.toBasicString()}"; Log.getLogger().error(err_msg); } } QuestManager.It.deleteTimerCheckUser(delete_checker); //questNormalActiveCheck() 의 대안 delete_checker = new(); DateTime now_dt = DateTimeHelper.Current; foreach (var user_guid in QuestManager.It.m_normal_quest_check_users.Keys) { if (false == player_manager.tryGetUserByPrimaryKey(user_guid, out var player)) { delete_checker.Add(user_guid); continue; } var user_create_or_load_action = player.getEntityAction(); ArgumentNullException.ThrowIfNull(user_create_or_load_action, $"user_create_or_load_action is null !!! - {player.toBasicString()}"); if (false == user_create_or_load_action.isCompletedLoadUser()) { continue; } var fn_transaction_runner = async delegate() { var repeat_quest_attribute = player.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(repeat_quest_attribute, () => $"repeat_quest_attribute is null !!!"); if (repeat_quest_attribute.m_is_checking == 0) return new(); if (now_dt < repeat_quest_attribute.m_next_allocate_time) return new(); //플레이어 정보는 퀘스트 메일 보내기 전에 로드 된다. 메일이 로드 안되어 있으면 리턴 할수 있도록 처리 해줘야된다. var quest_mail_action = player.getEntityAction(); if (false == quest_mail_action.isMailLoadedAll()) return new(); HashSet my_current_normal_mail_set = await quest_mail_action.getNormalMailSet(); int normal_mail_count = my_current_normal_mail_set.Count; HashSet assignable_mail_set = await QuestManager.It.getAssignableMailSet(player, my_current_normal_mail_set); //체크 대상이라 여기 들어왔는데 메일이 넘치면 미체크 대상으로 처리 if (MetaHelper.GameConfigMeta.MaxQuestSendMail <= normal_mail_count || assignable_mail_set.Count == 0) { QuestManager.It.m_normal_quest_check_users.TryRemove(player.getUserGuid(), out _); return new(); } //여기까지 왔으면 메일 보낼게 있다는 얘기이므로 전송한다. var assignable_quest_id = QuestManager.It.getAssignableQuestMailId(assignable_mail_set); ArgumentNullException.ThrowIfNull(assignable_quest_id, $"assignable_quest_id is null !!!"); //여기서 normalMailSet + 1 의 개수가 최대 개수를 넘으면 비활성화 처리 var check_value = QuestManager.It.questCheckUserAssignableQuestMaxCheck(player, my_current_normal_mail_set); ArgumentNullException.ThrowIfNull(check_value, $"check_value is null !!!"); (var result, var quest_mail, var quest_mail_log_invoker) = await quest_mail_action.sendQuestMail(assignable_quest_id); if (result.isFail()) { return result; } repeat_quest_attribute.m_next_allocate_time = repeat_quest_attribute.m_next_allocate_time.AddMinutes(MetaHelper.GameConfigMeta.CooltimeNormalQuestSendMail); if (false == check_value) { repeat_quest_attribute.m_is_checking = 0; } repeat_quest_attribute.modifiedEntityAttribute(); var server_logic = GameServerApp.getServerLogic(); ArgumentNullException.ThrowIfNull(server_logic, $"server_logic is null !!!"); var batch = new QueryBatchEx(player, LogActionType.QuestMailSend, server_logic.getDynamoDbClient()); { batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner()); } batch.appendBusinessLog(new RepeatQuestBusinessLog(repeat_quest_attribute.m_next_allocate_time, repeat_quest_attribute.m_is_checking)); batch.appendBusinessLog(quest_mail_log_invoker); result = await QueryHelper.sendQueryAndBusinessLog(batch); if (result.isFail()) { var err_msg = $"Failed to sendQueryAndBusinessLog() !!! : {result.toBasicString()} - {player.toBasicString()}"; Log.getLogger().error(err_msg); return result; } await quest_mail_action.addNewQuestMails(new List() { quest_mail }); await quest_mail_action.send_NTF_RECEIVED_QUEST_MAIL(player, new List() { assignable_quest_id }); await QuestManager.It.QuestCheckWithoutTransaction(player, new QuestMail(EQuestEventTargetType.MAIL, EQuestEventNameType.RECEIVED, "")); return result; }; var result = await player.runTransactionRunnerSafelyWithTransGuid(player.getUserGuid(), TransactionIdType.PrivateContents, "mailAndUpdateRepeatQuestInfo", fn_transaction_runner); if (result.isFail()) { var err_msg = $"Failed to runTransactionRunnerSafelyWithTransGuid() !!! : {result.toBasicString()} - {player.toBasicString()}"; Log.getLogger().error(err_msg); continue; } } foreach (var delete_user in delete_checker) { QuestManager.It.m_normal_quest_check_users.TryRemove(delete_user, out _); Log.getLogger() .debug($"setNormalMailTimer m_normal_quest_check_users remove accountId : {delete_user}"); } if (null != stopwatch) { var elapsed_msec = stopwatch.ElapsedMilliseconds; stopwatch.Stop(); Log.getLogger().debug($"{GetType()} Ticker Stopwatch Stop : ETID:{event_tid}, ElapsedMSec:{elapsed_msec}, TickIntervalMSec:{getOnTickIntervalMilliseconds()}"); } } public override string toBasicString() { return $"{this.getTypeName()}"; } public override string toSummaryString() { return $"{this.getTypeName()}"; } }