Files
2025-05-01 07:20:41 +09:00

1426 lines
57 KiB
C#

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<MAIL_GUID, Mail> m_sent_mails = new();
private ConcurrentDictionary<MAIL_GUID, Mail> m_received_mails = new();
private ConcurrentDictionary<MailType, List<MAIL_GUID>> 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<Result> onInit()
{
await Task.CompletedTask;
var result = new Result();
foreach (var mailtype in EnumHelper.getValues<MailType>())
{
m_client_received_mailkey.TryAdd(mailtype, new List<MAIL_GUID>());
}
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<string>)> getReceivedProductMailOrderIds()
{
var order_id_list = new List<string>();
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<MailAttrib>();
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<Result> AddMailFromDocs<TDoc>(List<TDoc> 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<MAIL_GUID, Mail> 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<MailAttribute>();
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<Result> checkSystemMail()
{
var result = new Result();
var err_msg = string.Empty;
result = await ProcessReceiveSystemMail();
return result;
}
private async Task<Result> 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<ILogInvoker>();
var mail_profile_attribute = player.getEntityAttribute<MailProfileAttribute>();
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<DynamoDbDocBase>();
foreach (var systemMail in systemMailList)
{
var system_mail_attribute = systemMail.getEntityAttribute<SystemMetaMailAttribute>();
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<string>(), 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<QueryRunnerWithDocument>(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<Result> 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<PackageAction>();
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<UserLandAuctionAction>();
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<MailProfileAttribute>();
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<Result> 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<ILogInvoker>();
var mail_profile_attribute = getOwner().getEntityAttribute<MailProfileAttribute>();
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<QueryRunnerWithDocument>(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<Result> 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<ILogInvoker>();
var mail_attribute = received_mail.getEntityAttribute<MailAttribute>();
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<QueryRunnerWithDocument>( 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<Result> 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<AccountAttribute>();
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<ILogInvoker>();
var mail_attribute = received_mail.getEntityAttribute<MailAttribute>();
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<MailAttribute>();
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<QueryRunnerWithDocument>(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<Result> UpdateBillingStateType(AccountAttribute account_attribute, string order_id, BillingStateType billingStateType, List<ILogInvoker> 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<BillingStateList>() { 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<Result> 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<InventoryActionBase>();
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<Result> 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<InventoryActionBase>();
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>? 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<Result> 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<MoneyAction>();
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<Result> 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<MAIL_GUID, Mail> 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<ILogInvoker>();
var mail_attribute = mail.getEntityAttribute<MailAttribute>();
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<AccountAttribute>();
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<QueryRunnerWithDocument>(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<List<Mail>> getNewMailList(MailType mailType)
{
var mail_list = new List<Mail>();
var new_mail_list = new List<Mail>();
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<MailAttribute>();
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<List<Mail>> getReceivedMailList()
{
var result = new Result();
var result_mails = new List<Mail>();
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<MailAttribute>();
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<MailAttribute>();
NullReferenceCheckHelper.throwIfNull(x_mail_attribute, () => $"x MailAttribute is null !! - player:{player.toBasicString()}");
var y_mail_attribute = y.getEntityAttribute<MailAttribute>();
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<ReceivedMailDoc>)> 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<ReceivedMailDoc>();
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<ReceivedMailDoc>(query_config);
if(result.isSuccess())
{
foreach(var recv_mail_doc in read_docs)
{
var mail_attrib = recv_mail_doc.getAttrib<MailAttrib>();
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<Mail> getSendedMailList()
{
var newMailEntity = new List<Mail>();
foreach(var sentMail in m_sent_mails)
{
newMailEntity.Add(sentMail.Value);
}
return newMailEntity;
}
public async Task<Result> 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<ILogInvoker>();
var mail_profile_attribute = player.getEntityAttribute<MailProfileAttribute>();
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<MailAttribute>();
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<QueryRunnerWithDocument>( 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<MailAction>();
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<ServerCommon.MailItem> 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<ServerCommon.MailItem> 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<MailProfileAttribute>();
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<ILogInvoker>();
var mail_profile_attribute = getOwner().getEntityAttribute<MailProfileAttribute>();
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<QueryRunnerWithDocument>(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<MailAttribute>();
//mail_attribute.ExpireTime = remainedMin
}
var batch = new QueryBatchEx<QueryRunnerWithDocument>(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<Result> 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<ILogInvoker>();
(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<DynamoDbDocBase>();
for (int i = 0; i < count; ++i)
{
var mail_items = new List<ServerCommon.MailItem>() { 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<string>(), 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<QueryRunnerWithDocument>(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;
}
}