using System.Collections.Concurrent; using ServerCore; using ServerBase; using ServerCommon; using ServerCommon.BusinessLogDomain; using MetaAssets; using GameServer.PacketHandler; using META_ID = System.UInt32; using MAIL_GUID = System.String; namespace GameServer; public class MailAction : EntityActionBase { private ConcurrentDictionary m_sent_mails = new(); private ConcurrentDictionary m_received_mails = new(); private ConcurrentDictionary> m_client_received_mailkey = new(); private bool m_isReceivedSystemMetaMail = false; private bool m_isNewReceivedMail = false; public MailAction(Player owner) : base(owner) { } public override async Task onInit() { await Task.CompletedTask; var result = new Result(); foreach (var mailtype in EnumHelper.getValues()) { m_client_received_mailkey.TryAdd(mailtype, new List()); } return result; } public override void onClear() { m_sent_mails.Clear(); m_received_mails.Clear(); foreach(var value in m_client_received_mailkey.Values) { value.Clear(); } return; } public bool isNewReceivedMail() { return m_isNewReceivedMail; } public bool isNewSystemMail() { return m_isReceivedSystemMetaMail; } public async Task<(Result, List)> getReceivedProductMailOrderIds() { var order_id_list = new List(); var result = new Result(); var err_msg = string.Empty; var player = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(player, () => "player is null !!!"); (result, var mail_list) = await getReceivedMailDoc(player.getUserGuid()); if (result.isFail()) { return (result, order_id_list); } foreach (var mail in mail_list) { var mail_attrib = mail.getAttrib(); NullReferenceCheckHelper.throwIfNull(mail_attrib, () => $"MailAttrib is null !! - player:{player.toBasicString()}"); if (mail_attrib.packageOrderId != string.Empty) { order_id_list.Add(mail_attrib.packageOrderId); } } return (result, order_id_list); } public async Task AddMailFromDocs(List mailDocs) where TDoc : MailDoc { var result = new Result(); var err_msg = string.Empty; var player = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(player, () => "player is null !!!"); ConcurrentDictionary mails = typeof(TDoc) == typeof(ReceivedMailDoc) ? m_received_mails : m_sent_mails; foreach(var mail_doc in mailDocs) { (result, var mail) = await Mail.createMailFromDoc(player, mail_doc); if(result.isFail() || null == mail) { err_msg = $"failed to copy from doc !! - {mail_doc.toBasicString()}"; Log.getLogger().error(err_msg); continue; } var mail_attribute = mail.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(mail_attribute, () => $"MailAttribute is null !! - player:{player.toBasicString()}"); if (mails.TryAdd(mail_attribute.MailGuid, mail) == false) { err_msg = $"Failed to get mail attribute : {nameof(MailAttribute)}"; result.setFail(ServerErrorCode.EntityAttributeIsNull, err_msg); Log.getLogger().error(result.toBasicString()); return result; } if(m_isNewReceivedMail == false && typeof(TDoc) == typeof(ReceivedMailDoc) && mail_attribute.IsRead == false) { m_isNewReceivedMail = true; } } return result; } public async Task checkSystemMail() { var result = new Result(); var err_msg = string.Empty; result = await ProcessReceiveSystemMail(); return result; } private async Task ProcessReceiveSystemMail() { var result = new Result(); var err_msg = string.Empty; var player = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(player, () => "player is null !!!"); var server_logic = GameServerApp.getServerLogic(); var fn_receive_system_mail = async delegate () { var result = new Result(); var invokers = new List(); var mail_profile_attribute = player.getEntityAttribute(); if (mail_profile_attribute == null) { err_msg = $"Failed to get mail profile attribute : {nameof(MailProfileAttribute)}"; result.setFail(ServerErrorCode.EntityAttributeIsNull, err_msg); Log.getLogger().error(result.toBasicString()); return result; } //운영툴 운영에따라 ID가 순서가 꼬일수도 있다. LastSystemMailId 로 가져오면 문제가 될수 있을듯 //int lastSystemMailId = mail_profile_attribute.LastSystemMailId; var received_system_mails = mail_profile_attribute.ReceivedSystemMails; var systemMailList = server_logic.getSystemMailManager().GetSystemMail(received_system_mails); var receivedMailDocs = new List(); foreach (var systemMail in systemMailList) { var system_mail_attribute = systemMail.getEntityAttribute(); if (system_mail_attribute == null) { err_msg = $"Failed to get system mail attribute : {nameof(SystemMetaMailAttribute)}"; result.setFail(ServerErrorCode.EntityAttributeIsNull, err_msg); Log.getLogger().error(result.toBasicString()); return result; } received_system_mails.TryAdd(system_mail_attribute.MailId, DateTimeHelper.Current); var language_type = player.getLanguageType(); var sender_nickname = StringRuleHelper.getString(language_type, system_mail_attribute.SenderNickName); var title = StringRuleHelper.getString(language_type, system_mail_attribute.Title); var text = StringRuleHelper.getString(language_type, system_mail_attribute.Text); (result, var receivedMailDoc) = await Mail.createSystemMail( player.getUserGuid(), player.getUserNickname(), sender_nickname , title, text, new List(), false , system_mail_attribute.ItemList, MetaHelper.GameConfigMeta.SystemMailStoragePeriod); if (result.isFail() || null == receivedMailDoc) { return result; } receivedMailDocs.Add(receivedMailDoc); var task_log_data = MailBusinessLogHelper.toMailLogInfo(receivedMailDoc); invokers.Add(new MailBusinessLog(task_log_data)); } if (receivedMailDocs.Count > 0) { //mail_profile_attribute.LastSystemMailId = lastSystemMailId; mail_profile_attribute.modifiedEntityAttribute(true); foreach(var base_doc in receivedMailDocs) { var mail_doc = base_doc as MailDoc; if (mail_doc == null) continue; var task_mail_log_data = MailBusinessLogHelper.toMailLogInfo(mail_doc); invokers.Add(new MailBusinessLog(task_mail_log_data)); } var task_log_data = MailBusinessLogHelper.toMailProfileLogInfo(mail_profile_attribute); invokers.Add(new MailProfileBusinessLog(task_log_data)); var batch = new QueryBatchEx(player, LogActionType.MailGetSystemMail , server_logic.getDynamoDbClient(), true); { batch.addQuery(new DBQEntityWrite(receivedMailDocs)); batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner()); } batch.appendBusinessLogs(invokers); result = await QueryHelper.sendQueryAndBusinessLog(batch); if (result.isFail()) { return result; } m_isNewReceivedMail = true; } m_isReceivedSystemMetaMail = false; return result; }; result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "ReceiveSystemMail", fn_receive_system_mail); if (result.isFail()) { err_msg = $"Failed to runTransactionRunnerSafely()!!! : {result.toBasicString()} - {player.toBasicString()}"; Log.getLogger().error(err_msg); } return result; } public async Task ProcessGetMail(MailType mailType) { var result = new Result(); var err_msg = string.Empty; var player = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(player, () => "player is null !!!"); var package_action = player.getEntityAction(); NullReferenceCheckHelper.throwIfNull(package_action, () => $"package_action is null !!! - {player.toBasicString()}"); if (mailType == MailType.ReceivedMail) { await package_action.tryOrderNewProductList(); } var user_land_auction_action = player.getEntityAction(); NullReferenceCheckHelper.throwIfNull(user_land_auction_action, () => $"user_land_auction_action is null !!! - {player.toBasicString()}"); await user_land_auction_action.updateRefundBidPriceAll(); if (m_isReceivedSystemMetaMail == true) { result = await ProcessReceiveSystemMail(); if(result.isFail()) { GetMailPacketHandler.send_S2C_ACK_GET_MAIL(player, result, null, mailType, 0); return result; } } await ProcessMailSendTime(); var mailList = await getNewMailList(mailType); var mail_profile_attribute = player.getEntityAttribute(); if (mail_profile_attribute == null) { err_msg = $"Failed to get mail profile attribute : {nameof(MailProfileAttribute)}"; result.setFail(ServerErrorCode.EntityAttributeIsNull, err_msg); Log.getLogger().error(result.toBasicString()); SendMailPacketHandler.send_S2C_ACK_SEND_MAIL(player, result, null); return result; } GetMailPacketHandler.send_S2C_ACK_GET_MAIL(player, result, mailList, mailType, mail_profile_attribute.SendMailCount); return result; } private async Task ProcessMailSendTime() { var result = new Result(); var err_msg = string.Empty; var player = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(player, () => "player is null !!!"); var server_logic = GameServerApp.getServerLogic(); if (checkMailSendTime() == true) { var fn_update_mail_send_time = async delegate () { var result = new Result(); var invokers = new List(); var mail_profile_attribute = getOwner().getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(mail_profile_attribute, () => $"mail_profile_attribute is null !!! - {player.toBasicString()}"); updateMailSendTime(mail_profile_attribute); var task_log_data = MailBusinessLogHelper.toMailProfileLogInfo(mail_profile_attribute); invokers.Add(new MailProfileBusinessLog(task_log_data)); var batch = new QueryBatchEx(player, LogActionType.MailInitSendCount , server_logic.getDynamoDbClient()); { batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner()); } batch.appendBusinessLogs(invokers); result = await QueryHelper.sendQueryAndBusinessLog(batch); if (result.isFail()) { return result; } return result; }; result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "UpdateMailSendTime", fn_update_mail_send_time); if (result.isFail()) { err_msg = $"Failed to runTransactionRunnerSafely()!!! : {result.toBasicString()} - {player.toBasicString()}"; Log.getLogger().error(err_msg); } } return result; } public async Task ReadReceivedMail(string mail_guid) { var result = new Result(); var err_msg = string.Empty; var player = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(player, () => "player is null !!!"); var server_logic = GameServerApp.getServerLogic(); if (m_received_mails.TryGetValue(mail_guid, out var received_mail) == false) { err_msg = $"Failed to TryGetValue() !!!, Not found Mail : reqMailGuid:{mail_guid} - {player.toBasicString()}"; result.setFail(ServerErrorCode.MailNotFound, err_msg); Log.getLogger().error(result.toBasicString()); ReadMailPacketHandler.send_S2C_ACK_READ_MAIL(player, result); return result; } var fn_read_mail = async delegate () { var result = new Result(); var invokers = new List(); var mail_attribute = received_mail.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(mail_attribute, () => $"mail_attribute is null !!! - {player.toBasicString()}"); mail_attribute.IsRead = true; mail_attribute.modifiedEntityAttribute(); var task_log_data = MailBusinessLogHelper.toMailLogInfo(mail_attribute); invokers.Add(new MailBusinessLog(task_log_data)); var batch = new QueryBatchEx( player, LogActionType.MailRead , server_logic.getDynamoDbClient() ); { batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner()); } batch.appendBusinessLogs(invokers); result = await QueryHelper.sendQueryAndBusinessLog(batch); if (result.isFail()) { ReadMailPacketHandler.send_S2C_ACK_READ_MAIL(player, result); return result; } ReadMailPacketHandler.send_S2C_ACK_READ_MAIL(player, result); return result; }; result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "ReadMail", fn_read_mail); if (result.isFail()) { err_msg = $"Failed to runTransactionRunnerSafely()!!! : {result.toBasicString()} - {player.toBasicString()}"; Log.getLogger().error(err_msg); } return result; } public async Task GetItemsReceivedMail(string mail_guid) { var result = new Result(); var err_msg = string.Empty; var player = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(player, () => "player is null !!!"); var server_logic = GameServerApp.getServerLogic(); var account_attribute = player.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(account_attribute, () => $"account_attribute is null !!! - {player.toBasicString()}"); if (m_received_mails.TryGetValue(mail_guid, out var received_mail) == false) { err_msg = $"Failed to ReadReceivedMail. Not found mail : mail_guid {mail_guid}"; result.setFail(ServerErrorCode.MailNotFound, err_msg); Log.getLogger().error(result.toBasicString()); GetItemsMailPacketHandler.send_S2C_ACK_GET_ITEMS_MAIL(player, result, null); return result; } var invokers = new List(); var mail_attribute = received_mail.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(mail_attribute, () => $"mail_attribute is null !!! - {player.toBasicString()}"); if (mail_attribute.IsGetItem == true || mail_attribute.ItemList.Count == 0) { err_msg = $"Item is empty. mail_guid : {mail_attribute.MailGuid}"; result.setFail(ServerErrorCode.MailAlreadyTaken, err_msg); Log.getLogger().error(result.toBasicString()); GetItemsMailPacketHandler.send_S2C_ACK_GET_ITEMS_MAIL(player, result, null); return result; } if (mail_attribute.packageOrderId != string.Empty) { result = await UpdateBillingStateType(account_attribute, mail_attribute.packageOrderId, BillingStateType.opening, invokers); if (result.isFail()) { GetItemsMailPacketHandler.send_S2C_ACK_GET_ITEMS_MAIL(player, result, null); return result; } } var fn_get_item_received_mail = async delegate () { var result = new Result(); var mail_attribute = received_mail.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(mail_attribute, () => $"mail_attribute is null !!! - {player.toBasicString()}"); foreach (var itemData in mail_attribute.ItemList) { result = await TakeMailItems(itemData); if (result.isFail()) return result; } mail_attribute.IsGetItem = true; mail_attribute.modifiedEntityAttribute(); var task_log_data = MailBusinessLogHelper.toMailLogInfo(mail_attribute); invokers.Add(new MailBusinessLog(task_log_data)); var batch = new QueryBatchEx(player, LogActionType.MailTaken , server_logic.getDynamoDbClient(), true); { batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner()); } batch.appendBusinessLogs(invokers); result = await QueryHelper.sendQueryAndBusinessLog(batch); if (result.isFail()) { GetItemsMailPacketHandler.send_S2C_ACK_GET_ITEMS_MAIL(player, result, null); return result; } var found_transaction_runner = player.findTransactionRunner(TransactionIdType.PrivateContents); if (null == found_transaction_runner) { var err_msg = $"Not found TransactionRunner !!! : {toBasicString()} - {player.toBasicString()}"; Log.getLogger().warn(err_msg); GetItemsMailPacketHandler.send_S2C_ACK_GET_ITEMS_MAIL(player, result, null); return result; } if(mail_attribute.packageOrderId != string.Empty) { //상태를 바꾸는데 실패해도 DB처리는 끝났기 때문에 실패해도 처리하지 않는다. await UpdateBillingStateType(account_attribute, mail_attribute.packageOrderId, BillingStateType.opened, new() ); } GetItemsMailPacketHandler.send_S2C_ACK_GET_ITEMS_MAIL(player, result, found_transaction_runner.getCommonResult()); return result; }; result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "GetItemsReceivedMail", fn_get_item_received_mail); if (result.isFail()) { err_msg = $"Failed to runTransactionRunnerSafely()!!! : {result.toBasicString()} - {player.toBasicString()}"; Log.getLogger().error(err_msg); } return result; } private async Task UpdateBillingStateType(AccountAttribute account_attribute, string order_id, BillingStateType billingStateType, List invokers) { var result = new Result(); var err_msg = string.Empty; var player = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(player, () => "player is null !!!"); var jwt = account_attribute.SsoAccountAuthJWT.ToString(); var account_id = account_attribute.AccountId; (result, bool isUpdated) = await BillingServerConnector.AbleToChangeBillingState(jwt, account_id.ToString(), order_id, billingStateType); if (result.isFail() || isUpdated == true) return result; //BillingServer에 상태 변경 var stateList = new List() { new BillingStateList() { order_id = order_id, state = billingStateType.ToString() } }; var billingChangeState = new BillingChangeState() { account_id = account_id.ToString(), state_list = stateList }; (result, var status_message) = await BillingServerConnector.UpdateBillingState(billingChangeState, jwt); if (result.isFail()) { var log_action = new LogActionEx(LogActionType.ProductOpenFailed); var task_failed_state_log_data = PackageBusinessLogHelper.toStateLogInfo(order_id, billingStateType, status_message); invokers.Add(new PackageStateBusinessLog(task_failed_state_log_data)); BusinessLogger.collectLogs(log_action, player, invokers); return result; } if(billingStateType == BillingStateType.opened) { var log_action = new LogActionEx(LogActionType.ProductOpenSuccess); var log_data = PackageBusinessLogHelper.toStateLogInfo(order_id, billingStateType, status_message); invokers.Add(new PackageStateBusinessLog(log_data)); BusinessLogger.collectLogs(log_action, player, invokers); return result; } var task_state_log_data = PackageBusinessLogHelper.toStateLogInfo(order_id, billingStateType, status_message); invokers.Add(new PackageStateBusinessLog(task_state_log_data)); return result; } private async Task TakeMailItems(ServerCommon.MailItem mail_item) { var result = new Result(); var err_msg = string.Empty; var player = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(player, () => "player is null !!!"); var inventory_action = player.getEntityAction(); NullReferenceCheckHelper.throwIfNull(inventory_action, () => $"inventory_action is null !!! - {player.toBasicString()}"); if (MetaData.Instance._ItemTable.TryGetValue((int)mail_item.ItemId, out var itemMetaData) == false) { err_msg = $"Failed to find Item meta Id. meta_id : {mail_item.ItemId}"; result.setFail(ServerErrorCode.NotFoundItemTableId, err_msg); Log.getLogger().error(result.toBasicString()); GetItemsMailPacketHandler.send_S2C_ACK_GET_ITEMS_MAIL(player, result, null); return result; } if (itemMetaData.TypeLarge == EItemLargeType.PRODUCT) { result = await TakeProductItem(mail_item); if (result.isFail()) { GetItemsMailPacketHandler.send_S2C_ACK_GET_ITEMS_MAIL(player, result, null); return result; } } else if (itemMetaData.TypeLarge == EItemLargeType.CURRENCY) { result = await TakeCurrencyItem(itemMetaData.TypeSmall, mail_item.Count); if (result.isFail()) { GetItemsMailPacketHandler.send_S2C_ACK_GET_ITEMS_MAIL(player, result, null); return result; } } else { if( false == itemMetaData.isCreatableItem() ) { err_msg = $"Cannet be Stored Item !!! : IsUiOnly:{itemMetaData.IsUiOnly}, LargeType:{itemMetaData.TypeLarge}, SmallType:{itemMetaData.TypeSmall} - {mail_item.ItemId}"; result.setFail(ServerErrorCode.ItemCanNotBeStored, err_msg); Log.getLogger().error(result.toBasicString()); GetItemsMailPacketHandler.send_S2C_ACK_GET_ITEMS_MAIL(player, result, null); return result; } (result, var new_item_list) = await inventory_action.tryTakalbleToBag((META_ID)mail_item.ItemId, (ushort)mail_item.Count); if (result.isFail()) { GetItemsMailPacketHandler.send_S2C_ACK_GET_ITEMS_MAIL(player, result, null); return result; } } return result; } private async Task TakeProductItem(ServerCommon.MailItem mail_item) { var result = new Result(); var err_msg = string.Empty; var player = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(player, () => "player is null !!!"); var inventory_action = player.getEntityAction(); NullReferenceCheckHelper.throwIfNull(inventory_action, () => $"inventory_action is null !!! - {player.toBasicString()}"); if (MetaData.Instance._ProductMetaDataById.TryGetValue((int)mail_item.ProductId, out var itemList) == false) { err_msg = $"Failed to find Item meta Id from ProductData. meta_id : {mail_item.ProductId}"; result.setFail(ServerErrorCode.NotFoundItemTableId, err_msg); Log.getLogger().error(result.toBasicString()); GetItemsMailPacketHandler.send_S2C_ACK_GET_ITEMS_MAIL(player, result, null); return result; } List? itemMetaList; if(mail_item.isRepeatProduct == true) itemMetaList = itemList.Repeat_List.ToList(); else itemMetaList = itemList.First_List.ToList(); foreach (var item in itemMetaList) { if (MetaData.Instance._ItemTable.TryGetValue(item.Id, out var itemMetaData) == false) { err_msg = $"Failed to find Item meta Id. meta_id : {item.Id}"; result.setFail(ServerErrorCode.NotFoundItemTableId, err_msg); Log.getLogger().error(result.toBasicString()); GetItemsMailPacketHandler.send_S2C_ACK_GET_ITEMS_MAIL(player, result, null); return result; } if (itemMetaData.TypeLarge == EItemLargeType.PRODUCT) { err_msg = $"Failed to find Item meta Id. meta_id : {item.Id}"; result.setFail(ServerErrorCode.NotFoundItemTableId, err_msg); Log.getLogger().error(result.toBasicString()); GetItemsMailPacketHandler.send_S2C_ACK_GET_ITEMS_MAIL(player, result, null); return result; } else if (itemMetaData.TypeLarge == EItemLargeType.CURRENCY) { result = await TakeCurrencyItem(itemMetaData.TypeSmall, (item.Value * mail_item.Count)); if (result.isFail()) { GetItemsMailPacketHandler.send_S2C_ACK_GET_ITEMS_MAIL(player, result, null); return result; } } else { (result, var new_item_list) = await inventory_action.tryTakalbleToBag((META_ID)item.Id, (ushort)(item.Value * mail_item.Count)); if (result.isFail()) { GetItemsMailPacketHandler.send_S2C_ACK_GET_ITEMS_MAIL(player, result, null); return result; } } } return result; } private async Task TakeCurrencyItem(EItemSmallType type, double amount) { var result = new Result(); var player = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(player, () => "player is null !!!"); var money_action = player.getEntityAction(); NullReferenceCheckHelper.throwIfNull(money_action, () => $"money_action is null !!! - {player.toBasicString()}"); var currencyType = MetaData.Instance.CurrencyItemSmallTypeToCurrencyType(type); result = await money_action.changeMoney(currencyType, amount); return result; } public async Task DeleteMail(MAIL_GUID mail_guid, MailType mailType) { var result = new Result(); var err_msg = string.Empty; var player = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(player, () => "player is null !!!"); var server_logic = GameServerApp.getServerLogic(); ConcurrentDictionary mails; switch (mailType) { case MailType.SentMail: mails = m_sent_mails; break; case MailType.ReceivedMail: mails = m_received_mails; break; default: { err_msg = $"Failed to ReadReceivedMail. Not found mail : mail_guid {mail_guid}"; result.setFail(ServerErrorCode.MailInvalidMailType, err_msg); Log.getLogger().error(result.toBasicString()); DeleteMailPacketHandler.send_S2C_ACK_DELETE_MAIL(player, result); return result; } } if (mails.TryGetValue(mail_guid, out var mail) == false) { err_msg = $"Failed to ReadReceivedMail. Not found mail : mail_guid {mail_guid}"; result.setFail(ServerErrorCode.MailNotFound, err_msg); Log.getLogger().error(result.toBasicString()); DeleteMailPacketHandler.send_S2C_ACK_DELETE_MAIL(player, result); return result; } var fn_delete_mail = async delegate () { var result = new Result(); var invokers = new List(); var mail_attribute = mail.getEntityAttribute(); if (mail_attribute == null) { err_msg = $"Failed to get mail attribute : {nameof(MailAttribute)}"; result.setFail(ServerErrorCode.EntityAttributeIsNull, err_msg); Log.getLogger().error(result.toBasicString()); DeleteMailPacketHandler.send_S2C_ACK_DELETE_MAIL(player, result); return result; } var billingStateType = BillingStateType.none; if (mail_attribute.packageOrderId != string.Empty) { var account_attribute = player.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(account_attribute, () => $"account_attribute is null !!! - {player.toBasicString()}"); var jwt = account_attribute.SsoAccountAuthJWT.ToString(); var account_id = account_attribute.AccountId; (result, billingStateType) = await BillingServerConnector.GetBillingState(jwt, account_id.ToString(), mail_attribute.packageOrderId); if (billingStateType == BillingStateType.none) { DeleteMailPacketHandler.send_S2C_ACK_DELETE_MAIL(player, result); return result; } if(billingStateType == BillingStateType.refund_request || billingStateType == BillingStateType.refund) { result.setFail(ServerErrorCode.BillingStateTypeRefund); DeleteMailPacketHandler.send_S2C_ACK_DELETE_MAIL(player, result); return result; } } if ( billingStateType != BillingStateType.canceled && false == mail_attribute.isDeletableMail() ) { err_msg = $"Failed to Delete Mail. Mail Item is exist : {nameof(MailAttribute)}"; result.setFail(ServerErrorCode.MailCantDeleteIfItemExists, err_msg); Log.getLogger().warn(result.toBasicString()); DeleteMailPacketHandler.send_S2C_ACK_DELETE_MAIL(player, result); return result; } mail_attribute.deleteEntityAttribute(); var task_log_data = MailBusinessLogHelper.toMailLogInfo(mail_attribute); invokers.Add(new MailBusinessLog(task_log_data)); var batch = new QueryBatchEx(player, LogActionType.MailDestroy , server_logic.getDynamoDbClient(), true); { batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner()); } batch.appendBusinessLogs(invokers); result = await QueryHelper.sendQueryAndBusinessLog(batch); if (result.isFail()) { DeleteMailPacketHandler.send_S2C_ACK_DELETE_MAIL(player, result); return result; } if(mails.TryRemove(mail_guid, out var deleted_mail) == false) { Log.getLogger().error("Mail remove failed."); } if (m_client_received_mailkey.TryGetValue(mailType, out var client_received_mailkey_list) == false) { client_received_mailkey_list = new(); m_client_received_mailkey.TryAdd(mailType, client_received_mailkey_list); } client_received_mailkey_list.Remove(mail_guid); DeleteMailPacketHandler.send_S2C_ACK_DELETE_MAIL(player, result); return result; }; result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "DeleteMail", fn_delete_mail); if (result.isFail()) { err_msg = $"Failed to runTransactionRunnerSafely()!!! : {result.toBasicString()} - {player.toBasicString()}"; Log.getLogger().error(err_msg); } return result; } private async Task> getNewMailList(MailType mailType) { var mail_list = new List(); var new_mail_list = new List(); if (m_client_received_mailkey.TryGetValue(mailType, out var client_received_mailkey_list) == false) { client_received_mailkey_list = new(); m_client_received_mailkey.TryAdd(mailType, client_received_mailkey_list); } switch (mailType) { case MailType.ReceivedMail: mail_list = await getReceivedMailList(); break; case MailType.SentMail: mail_list = getSendedMailList(); break; default: return mail_list; } int mailCount = 0; foreach (var mail in mail_list) { ++mailCount; if (mailCount > ServerCommon.Constant.MAX_READ_MAIL_DB_COUNT) { break; } var mail_attribute = mail.getEntityAttribute(); if(mail_attribute == null) { continue; } if(client_received_mailkey_list.Any(guid => guid == mail_attribute.MailGuid) == true) { continue; } new_mail_list.Add(mail); client_received_mailkey_list.Add(mail_attribute.MailGuid); } return new_mail_list; } private async Task> getReceivedMailList() { var result = new Result(); var result_mails = new List(); var player = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(player, () => "player is null !!!"); if (m_isNewReceivedMail == false) { foreach (var receivedMail in m_received_mails) { result_mails.Add(receivedMail.Value); } return result_mails; } (result, var read_docs) = await getReceivedMailDoc(player.getUserGuid()); if (result.isFail()) { return result_mails; } m_isNewReceivedMail = false; m_received_mails.Clear(); foreach (var read_doc in read_docs) { (result, var mail) = await Mail.createMailFromDoc(player, read_doc); if(mail == null) { continue; } var mail_attribute = mail.getEntityAttribute(); if(mail_attribute == null) { continue; } m_received_mails.TryAdd(mail_attribute.MailGuid, mail); result_mails.Add(mail); } result_mails.Sort((x, y) => { var x_mail_attribute = x.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(x_mail_attribute, () => $"x MailAttribute is null !! - player:{player.toBasicString()}"); var y_mail_attribute = y.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(y_mail_attribute, () => $"y MailAttribute is null !! - player:{player.toBasicString()}"); return y_mail_attribute.CreateTime.CompareTo(x_mail_attribute.CreateTime); }); return result_mails; } private async Task<(Result, List)> getReceivedMailDoc(string userGuid) { var err_msg = string.Empty; var server_logic = GameServerApp.getServerLogic(); var dynamo_db_client = server_logic.getDynamoDbClient(); var received_mail_docs = new List(); var doc = new ReceivedMailDoc(userGuid); var event_tid = Guid.NewGuid().ToString("N"); var query_config = dynamo_db_client.makeQueryConfigForReadByPKOnly(doc.getPK()); (var result, var read_docs) = await dynamo_db_client.simpleQueryDocTypesWithQueryOperationConfig(query_config); if(result.isSuccess()) { foreach(var recv_mail_doc in read_docs) { var mail_attrib = recv_mail_doc.getAttrib(); NullReferenceCheckHelper.throwIfNull(mail_attrib, () => $"mail_attrib is null !!! - userGuid:{userGuid}"); if (DateTimeHelper.Current > mail_attrib.ExpireTime) { var to_delete_result = await dynamo_db_client.simpleDeleteDocumentWithDocType(recv_mail_doc, event_tid); if(to_delete_result.isFail()) { err_msg = $"Failed to simpleDeleteDocumentWithDocType() !!!, can't received mail : Mail:{mail_attrib.toBasicString()} - userGuid:{userGuid}"; Log.getLogger().error(err_msg); } else { err_msg = $"Mail deleted with expired retention period !!! : deletedMail:{mail_attrib.toBasicString()} - userGuid:{userGuid}"; Log.getLogger().info(err_msg); } continue; } received_mail_docs.Add(recv_mail_doc); } } return (result, received_mail_docs); } private List getSendedMailList() { var newMailEntity = new List(); foreach(var sentMail in m_sent_mails) { newMailEntity.Add(sentMail.Value); } return newMailEntity; } public async Task trySendMail(string toNickName, string to_user_guid, string title, string mailText) { var result = new Result(); var err_msg = string.Empty; var player = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(player, () => "player is null !!!"); var server_logic = GameServerApp.getServerLogic(); if(to_user_guid == player.getUserGuid()) { result.setFail(ServerErrorCode.MailCantSendSelf, err_msg); SendMailPacketHandler.send_S2C_ACK_SEND_MAIL(player, result, null); return result; } var fn_send_mail = async delegate () { var result = new Result(); var invokers = new List(); var mail_profile_attribute = player.getEntityAttribute(); if (mail_profile_attribute == null) { err_msg = $"Failed to get mail profile attribute : {nameof(MailProfileAttribute)}"; result.setFail(ServerErrorCode.EntityAttributeIsNull, err_msg); Log.getLogger().error(result.toBasicString()); SendMailPacketHandler.send_S2C_ACK_SEND_MAIL(player, result, null); return result; } if (checkMailSendTime() == true) { updateMailSendTime(mail_profile_attribute); } if (mail_profile_attribute.SendMailCount >= ServerCommon.Constant.MAX_MAILSEND_COUNT) { err_msg = $"Send Mail Over The Max Count. !!!, can't true state - {getOwner().toBasicString()}"; result.setFail(ServerErrorCode.MailMaxSendCountExceed, err_msg); Log.getLogger().warn(result.toBasicString()); SendMailPacketHandler.send_S2C_ACK_SEND_MAIL(player, result, null); return result; } (result, var read_docs) = await getReceivedMailDoc(to_user_guid); if(read_docs.Count >= ServerCommon.Constant.MAX_READ_MAIL_DB_COUNT) { err_msg = $"Target Received Mail Over The Max Count. !!!, target guid - {to_user_guid}"; result.setFail(ServerErrorCode.MailMaxTargetReceivedCountExceed, err_msg); Log.getLogger().error(result.toBasicString()); SendMailPacketHandler.send_S2C_ACK_SEND_MAIL(player, result, null); return result; } // 2. mail_profile_attribute 변경 mail_profile_attribute.SendMailCount += 1; mail_profile_attribute.modifiedEntityAttribute(); var task_log_data = MailBusinessLogHelper.toMailProfileLogInfo(mail_profile_attribute); invokers.Add(new MailProfileBusinessLog(task_log_data)); // 3. 보낸 메일 (result, var sent_mail) = await Mail.createSendMail(player, toNickName, to_user_guid, title, mailText); if (result.isFail() || sent_mail == null) { err_msg = $"Create Mail Failed. !!! - {getOwner().toBasicString()}"; Log.getLogger().error(err_msg); SendMailPacketHandler.send_S2C_ACK_SEND_MAIL(player, result, null); return result; } var send_mail_attribute = sent_mail.getEntityAttribute(); if (send_mail_attribute == null) { err_msg = $"Failed to get mail attribute : {nameof(MailAttribute)}"; result.setFail(ServerErrorCode.EntityAttributeIsNull, err_msg); Log.getLogger().error(result.toBasicString()); SendMailPacketHandler.send_S2C_ACK_SEND_MAIL(player, result, null); return result; } var task_send_log_data = MailBusinessLogHelper.toMailLogInfo(send_mail_attribute); invokers.Add(new MailBusinessLog(task_send_log_data)); // 4. 받은 메일 저장하는 document 생성 var received_mail_doc = await MailHelper.CreateReceivedMailBySendMail(to_user_guid, send_mail_attribute.MailGuid, send_mail_attribute); if (null == received_mail_doc) { err_msg = $"Failed to send mail : createReceivedMailBySendMail - to_user_guid:{to_user_guid}, send_mail_guid:{send_mail_attribute.MailGuid}"; result.setFail(ServerErrorCode.MailSystemError, err_msg); Log.getLogger().error(result.toBasicString()); SendMailPacketHandler.send_S2C_ACK_SEND_MAIL(player, result, null); return result; } var batch = new QueryBatchEx( player, LogActionType.MailSend , server_logic.getDynamoDbClient(), true); { batch.addQuery(new DBQEntityWrite(received_mail_doc)); batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner()); } batch.appendBusinessLogs(invokers); result = await QueryHelper.sendQueryAndBusinessLog(batch); if (result.isFail()) { SendMailPacketHandler.send_S2C_ACK_SEND_MAIL(player, result, null); return result; } m_sent_mails.TryAdd(send_mail_attribute.MailGuid, sent_mail); var player_manager = server_logic.getPlayerManager(); if (player_manager.tryGetUserByPrimaryKey(to_user_guid, out var found_user) == true) { var found_user_mail_action = found_user.getEntityAction(); found_user_mail_action.NewReceivedMail(); } else { var login_cache_request = new LoginCacheOtherUserRequest(player, server_logic.getRedisConnector(), to_user_guid); await login_cache_request.fetchLogin(); var login_cache = login_cache_request.getLoginCache(); if (login_cache != null) { MailNotifyHelper.send_GS2GS_NTF_NEW_MAIL(login_cache.CurrentServer, to_user_guid); } } SendMailPacketHandler.send_S2C_ACK_SEND_MAIL(player, result, sent_mail); return result; }; result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "SendMail", fn_send_mail); if (result.isFail()) { err_msg = $"Failed to runTransactionRunnerSafely()!!! : {result.toBasicString()} - {player.toBasicString()}"; Log.getLogger().error(err_msg); } return result; } public async Task<(Result, ReceivedMailDoc?)> tryMakeNewSystemMail(List newMailItems, string systemMailMetaKey, Int64 TTL_Period, string packageOrderId) { var result = new Result(); var err_msg = string.Empty; var player = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(player, () => "player is null !!!"); if (MetaData.Instance.SystemMailMetaData.TryGetValue(systemMailMetaKey, out var systemMailMetaData) == false) { result.setFail(ServerErrorCode.SystemMailMetaDataNotFound, err_msg); return (result, null); } (result, var mail_doc) = await Mail.createSystemMailWithMeta(player.getUserGuid(), player.getUserNickname(), systemMailMetaData, newMailItems, TTL_Period, packageOrderId); if (result.isFail()) { err_msg = $"Create Mail Failed. !!! : {result.toBasicString()} - {getOwner().toBasicString()}"; Log.getLogger().error(err_msg); SendMailPacketHandler.send_S2C_ACK_SEND_MAIL(player, result, null); return (result, null); } return (result, mail_doc); } public async Task<(Result, ReceivedMailDoc?)> tryMakeNewSystemMail(List newMailItems, string systemMailMetaKey, DateTime expireDate, string packageOrderId) { var result = new Result(); var err_msg = string.Empty; var player = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(player, () => "player is null !!!"); if (MetaData.Instance.SystemMailMetaData.TryGetValue(systemMailMetaKey, out var systemMailMetaData) == false) { result.setFail(ServerErrorCode.SystemMailMetaDataNotFound, err_msg); return (result, null); } (result, var mail_doc) = await Mail.createSystemMailWithMeta( player.getUserGuid(), player.getUserNickname() , systemMailMetaData, newMailItems , expireDate, packageOrderId); if (result.isFail()) { err_msg = $"Create Mail Failed. !!! : {result.toBasicString()} - {getOwner().toBasicString()}"; Log.getLogger().error(err_msg); SendMailPacketHandler.send_S2C_ACK_SEND_MAIL(player, result, null); return (result, null); } return (result, mail_doc); } private bool checkMailSendTime() { var mail_profile_attribute = getOwner().getOriginEntityAttribute(); NullReferenceCheckHelper.throwIfNull(mail_profile_attribute, () => $"mail_profile_attribute is null !!! - {getOwner().toBasicString()}"); if (mail_profile_attribute.SendMailUpdateDay < DateTime.UtcNow.Date.AddHours(MetaHelper.GameConfigMeta.SentMailNumsResetTime).Ticks) return true; return false; } private void updateMailSendTime(MailProfileAttribute mail_profile_attribute) { if (mail_profile_attribute.SendMailUpdateDay < DateTime.UtcNow.Date.AddHours(MetaHelper.GameConfigMeta.SentMailNumsResetTime).Ticks) { mail_profile_attribute.SendMailCount = 0; mail_profile_attribute.SendMailUpdateDay = DateTime.UtcNow.Date.AddHours(MetaHelper.GameConfigMeta.SentMailNumsResetTime).Ticks; mail_profile_attribute.modifiedEntityAttribute(true); } } public void NewReceivedMail() { setNewReceivedMail(); var player = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(player, () => "player is null !!!"); player.send_S2C_NTF_NEW_MAIL(); } public void setNewReceivedMail() { m_isNewReceivedMail = true; } public void NewReceivedSystemMail() { setNewReceivedSystemMetaMail(); var player = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(player, () => "player is null !!!"); player.send_S2C_NTF_NEW_SYSTEM_MAIL_MAIL(); } public void setNewReceivedSystemMetaMail() { m_isReceivedSystemMetaMail = true; } //---치트 public async Task CheatMailSendUpdateDay() { var result = new Result(); var err_msg = string.Empty; var player = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(player, () => "player is null !!!"); var server_logic = GameServerApp.getServerLogic(); var fn_cheat_mail = async delegate () { var result = new Result(); var invokers = new List(); var mail_profile_attribute = getOwner().getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(mail_profile_attribute, () => $"mail_profile_attribute is null !!! - {player.toBasicString()}"); mail_profile_attribute.SendMailCount = 0; mail_profile_attribute.SendMailUpdateDay = DateTime.UtcNow.Date.Ticks; mail_profile_attribute.modifiedEntityAttribute(true); var task_log_data = MailBusinessLogHelper.toMailProfileLogInfo(mail_profile_attribute); invokers.Add(new MailProfileBusinessLog(task_log_data)); var batch = new QueryBatchEx(player, LogActionType.MailInitSendCount , server_logic.getDynamoDbClient(), true); { batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner()); } batch.appendBusinessLogs(invokers); result = await QueryHelper.sendQueryAndBusinessLog(batch); if (result.isFail()) { DeleteMailPacketHandler.send_S2C_ACK_DELETE_MAIL(player, result); return result; } return result; }; result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "Cheat.MailInitSendCount", fn_cheat_mail); if (result.isFail()) { err_msg = $"Failed to runTransactionRunnerSafely()!!! : {result.toBasicString()} - {player.toBasicString()}"; Log.getLogger().error(err_msg); } return; } //중단 public async Task CheatSetRemainedTime(bool isSendMail, int remainedMin) { var result = new Result(); var err_msg = string.Empty; var player = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(player, () => "player is null !!!"); var server_logic = GameServerApp.getServerLogic(); var fn_cheat_mail = async delegate () { var result = new Result(); var mails = isSendMail == true ? m_sent_mails : m_received_mails; foreach (var mail in mails) { var mail_attribute = mail.Value.getEntityAttribute(); //mail_attribute.ExpireTime = remainedMin } var batch = new QueryBatchEx(player, LogActionType.CheatCommandResetMailCount , server_logic.getDynamoDbClient(), true); { batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner()); } result = await QueryHelper.sendQueryAndBusinessLog(batch); if (result.isFail()) { DeleteMailPacketHandler.send_S2C_ACK_DELETE_MAIL(player, result); return result; } return result; }; result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "Cheat.MailRemainedTime", fn_cheat_mail); if (result.isFail()) { err_msg = $"Failed to runTransactionRunnerSafely()!!! : {result.toBasicString()} - {player.toBasicString()}"; Log.getLogger().error(err_msg); } return; } public async Task cheatSendMailToMe(int count, bool permanentMail) { var result = new Result(); var err_msg = string.Empty; var player = getOwner() as Player; NullReferenceCheckHelper.throwIfNull(player, () => "player is null !!!"); var server_logic = GameServerApp.getServerLogic(); var fn_send_mail = async delegate () { var result = new Result(); var invokers = new List(); (result, var read_docs) = await getReceivedMailDoc(player.getUserGuid()); if (read_docs.Count >= ServerCommon.Constant.MAX_READ_MAIL_DB_COUNT) { result.setFail(ServerErrorCode.MailMaxTargetReceivedCountExceed, err_msg); return result; } DateTime now = DateTimeHelper.Current; var expireDate = now.AddSeconds(MetaHelper.GameConfigMeta.SendMailStoragePeriod); if (permanentMail == true) expireDate = DateTimeHelper.MaxTime; var receive_mail_doc_list = new List(); for (int i = 0; i < count; ++i) { var mail_items = new List() { new ServerCommon.MailItem() { ItemId = (META_ID)15300313, Count = 1 } }; (result, var received_mail_doc) = await Mail.createSystemMail( player.getUserGuid(), player.getUserNickname() , "QATeam", "Cheat Test Mail", "QA Team Fighting." , new List(), false, mail_items, expireDate, ""); if (received_mail_doc == null) { return result; } receive_mail_doc_list.Add(received_mail_doc); var task_log_data = MailBusinessLogHelper.toMailLogInfo(received_mail_doc); invokers.Add(new MailBusinessLog(task_log_data)); } var batch = new QueryBatchEx(player, LogActionType.CheatCommandSendMail , server_logic.getDynamoDbClient(), true); { batch.addQuery(new DBQEntityWrite(receive_mail_doc_list)); } batch.appendBusinessLogs(invokers); result = await QueryHelper.sendQueryAndBusinessLog(batch); if (result.isFail()) { return result; } NewReceivedMail(); return result; }; result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "Cheat.SendMail", fn_send_mail); if (result.isFail()) { err_msg = $"Failed to runTransactionRunnerSafely()!!! : {result.toBasicString()} - {player.toBasicString()}"; Log.getLogger().error(err_msg); } return result; } }