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

542 lines
20 KiB
C#

using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using ServerCore;
using ServerBase;
using ServerCommon;
using ServerCommon.BusinessLogDomain;
using MetaAssets;
using GameServer.PacketHandler;
using META_ID = System.UInt32;
namespace GameServer;
public class CartAction : EntityActionBase
{
private Cart? m_Cart = null;
public CartAction(Player owner)
: base(owner)
{
}
public override async Task<Result> onInit()
{
var result = new Result();
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
m_Cart = new(player);
await m_Cart.onInit();
return result;
}
public override void onClear()
{
NullReferenceCheckHelper.throwIfNull(m_Cart, () => $"m_Cart is null !!!");
m_Cart.onCearAll();
}
public Result AddCartFromDoc(CartDoc? cartDoc)
{
var result = new Result();
var err_msg = string.Empty;
if (cartDoc == null) return result;
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
NullReferenceCheckHelper.throwIfNull(m_Cart, () => $"m_Cart is null !!!");
var cart_attribute = m_Cart.getEntityAttribute<CartAttribute>();
if (cart_attribute == null)
{
err_msg = $"Failed to get cart attribute : {nameof(CartAttribute)}";
result.setFail(ServerErrorCode.EntityAttributeIsNull, err_msg);
Log.getLogger().error(err_msg);
return result;
}
if(cart_attribute.copyEntityAttributeFromDoc(cartDoc) == false)
{
err_msg = $"Failed copyEntityAttributeFromDoc !!! - {typeof(CartAction).Name}";
result.setFail(ServerErrorCode.DynamoDbDocCopyToEntityAttributeFailed, err_msg);
Log.getLogger().error(result.toBasicString());
return result;
}
return result;
}
public Result GetCart4Client()
{
var result = new Result();
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
GetCartPacketHandler.send_S2C_ACK_GET_CART(player, result, m_Cart);
return result;
}
public async Task<Result> AddCartProcess(META_ID item_meta_id, int count, CurrencyType currency_type)
{
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();
NullReferenceCheckHelper.throwIfNull(server_logic, () => $"server_logic is null !!!");
var fn_add_cart = async delegate ()
{
var result = new Result();
var err_msg = string.Empty;
var invokers = new List<ILogInvoker>();
(result, int item_sum_count) = AddCart(item_meta_id, count, currency_type);
if (result.isFail())
{
PacketHandler.AddCartPacketHandler.send_S2C_ACK_ADD_CART(player, result, 0, 0);
return result;
}
List<(META_ID, int)> deltaCartList = new List<(META_ID, int)>() { (item_meta_id, count) };
var task_log_data = CartBusinessLogHelper.toLogInfo(deltaCartList);
invokers.Add(new CartBusinessLog(task_log_data));
var batch = new QueryBatchEx<QueryRunnerWithDocument>(player, LogActionType.CartAdd
, server_logic.getDynamoDbClient());
{
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
}
batch.appendBusinessLogs(invokers);
result = await QueryHelper.sendQueryAndBusinessLog(batch);
if (result.isFail())
{
AddCartPacketHandler.send_S2C_ACK_ADD_CART(player, result, 0, 0);
return result;
}
AddCartPacketHandler.send_S2C_ACK_ADD_CART(player, result, item_meta_id, item_sum_count);
return result;
};
result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "AddCart", fn_add_cart);
if (result.isFail())
{
err_msg = $"Failed to runTransactionRunnerSafely() !!! : {result.toBasicString()} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
}
return result;
}
public async Task<Result> DeleteCartProcess(List<CartItemInfo> req_del_cart_items)
{
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();
NullReferenceCheckHelper.throwIfNull(server_logic, () => $"server_logic is null !!!");
var fn_delete_cart = async delegate ()
{
var result = new Result();
var err_msg = string.Empty;
var invokers = new List<ILogInvoker>();
(result, var isRemoveItem) = DeleteCart(req_del_cart_items);
if (result.isFail())
{
DelCartPacketHandler.send_S2C_ACK_DEL_CART(player, result, false);
return result;
}
List<(META_ID, int)> deltaCartList = req_del_cart_items.Select(x => ((META_ID)x.ItemId, x.Count)).ToList();
var task_log_data = CartBusinessLogHelper.toLogInfo(deltaCartList);
invokers.Add(new CartBusinessLog(task_log_data));
var batch = new QueryBatchEx<QueryRunnerWithDocument>(player, LogActionType.CartDelete
, server_logic.getDynamoDbClient());
{
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
}
batch.appendBusinessLogs(invokers);
result = await QueryHelper.sendQueryAndBusinessLog(batch);
if (result.isFail())
{
DelCartPacketHandler.send_S2C_ACK_DEL_CART(player, result, false);
return result;
}
DelCartPacketHandler.send_S2C_ACK_DEL_CART(player, result, isRemoveItem);
return result;
};
result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "DeleteCart", fn_delete_cart);
if (result.isFail())
{
err_msg = $"Failed to runTransactionRunnerSafely() !!! : {result.toBasicString()} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
}
return result;
}
public async Task<Result> BuyCartProcess(List<CartItemInfo> req_buy_cart_items)
{
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 (req_buy_cart_items.Count == 0)
{
BuyCartPacketHandler.send_S2C_ACK_BUY_CART(player, result, null);
return result;
}
var fn_buy_cart = async delegate ()
{
var result = new Result();
var err_msg = string.Empty;
var invokers = new List<ILogInvoker>();
// 카트에서 제거
var deleteResult = DeleteCart(req_buy_cart_items);
if (deleteResult.result.isFail())
{
BuyCartPacketHandler.send_S2C_ACK_BUY_CART(player, result, null);
return result;
}
List<(META_ID, int)> deltaCartList = req_buy_cart_items.Select(x => ((META_ID)x.ItemId, x.Count)).ToList();
var task_log_data = CartBusinessLogHelper.toLogInfo(deltaCartList);
invokers.Add(new CartBusinessLog(task_log_data));
// 재화 차감
result = await PayCurrencyForItem(req_buy_cart_items);
if (result.isFail())
{
BuyCartPacketHandler.send_S2C_ACK_BUY_CART(player, result, null);
return result;
}
// 아이템 지급
var takeItemResult = await TakeCartItem(req_buy_cart_items);
if (takeItemResult.result.isFail())
{
BuyCartPacketHandler.send_S2C_ACK_BUY_CART(player, result, null);
return result;
}
result = await updateItemFirstPurchaseHistory(req_buy_cart_items);
if (result.isFail())
{
BuyCartPacketHandler.send_S2C_ACK_BUY_CART(player, result, null);
return result;
}
var batch = new QueryBatchEx<QueryRunnerWithDocument>(player, LogActionType.CartPurchase
, server_logic.getDynamoDbClient(), true);
{
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
}
batch.appendBusinessLogs(invokers);
result = await QueryHelper.sendQueryAndBusinessLog(batch);
if (result.isFail())
{
BuyCartPacketHandler.send_S2C_ACK_BUY_CART(player, result, null);
return result;
}
BuyCartPacketHandler.send_S2C_ACK_BUY_CART(player, result, takeItemResult.changed_Items);
return result;
};
result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "BuyCart", fn_buy_cart);
if (result.isFail())
{
err_msg = $"Failed to runTransactionRunnerSafely() !!! : {result.toBasicString()} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
}
return result;
}
private (Result result, Int32 item_sum_count) AddCart(META_ID item_meta_id, int count, CurrencyType currency_type)
{
var result = new Result();
var err_msg = string.Empty;
NullReferenceCheckHelper.throwIfNull(m_Cart, () => $"m_Cart is null !!!");
var cart_attribute = m_Cart.getEntityAttribute<CartAttribute>();
if (cart_attribute == null)
{
err_msg = $"Failed to get cart attribute : {nameof(CartAttribute)}";
result.setFail(ServerErrorCode.EntityAttributeIsNull, err_msg);
Log.getLogger().error(err_msg);
return (result, 0);
}
cart_attribute.CartItems.TryGetValue(currency_type, out var category_cart_items);
NullReferenceCheckHelper.throwIfNull(category_cart_items, () => $"category_cart_items is null !!!");
if (category_cart_items.Count >= 20)
{
err_msg = $"cart is Full. currency_type : {currency_type}";
result.setFail(ServerErrorCode.CartMaxCountExceed, err_msg);
Log.getLogger().error(err_msg);
return (result, 0);
}
int sum_count = count;
if (category_cart_items.TryGetValue(item_meta_id, out var cur_count) == false)
{
category_cart_items.TryAdd(item_meta_id, count);
}
else
{
sum_count += cur_count;
category_cart_items[item_meta_id] = sum_count;
}
var player = m_Cart.getRootParent() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
result = player.checkItemFirstPurchaseItemCount((int)item_meta_id, sum_count);
if (result.isFail())
{
return (result, 0);
}
if (sum_count > 99)
{
err_msg = $"FullStack of this item in cart. itemId : {item_meta_id}";
result.setFail(ServerErrorCode.CartStackCountInvalid, err_msg);
Log.getLogger().error(err_msg);
return (result, 0);
}
cart_attribute.modifiedEntityAttribute();
return (result, sum_count);
}
private (Result result, bool isRemovedItem) DeleteCart(List<CartItemInfo> del_cart_items)
{
var result = new Result();
var err_msg = string.Empty;
bool isRemovedItem = false;
NullReferenceCheckHelper.throwIfNull(m_Cart, () => $"m_Cart is null !!!");
var cart_attribute = m_Cart.getEntityAttribute<CartAttribute>();
if (cart_attribute == null)
{
err_msg = $"Failed to get cart attribute : {nameof(CartAttribute)}";
result.setFail(ServerErrorCode.EntityAttributeIsNull, err_msg);
Log.getLogger().error(err_msg);
return (result, isRemovedItem);
}
foreach (var del_cart_item in del_cart_items)
{
if (EnumHelper.tryParse<CurrencyType>(del_cart_item.BuyType, out var currencyType) == false)
{
err_msg = $"Enum Pase Failed. BuyType : {del_cart_item.BuyType}";
result.setFail(ServerErrorCode.CartInvalidCurrencyType, err_msg);
Log.getLogger().error(err_msg);
return (result, isRemovedItem);
}
if(MetaData.Instance._ItemTable.TryGetValue(del_cart_item.ItemId, out var itemData) == false)
{
err_msg = $"Not found meta of Item !!! : ItemMetaId:{del_cart_item.ItemId} - {getOwner().toBasicString()}";
result.setFail(ServerErrorCode.CartMetaDataNotFound, err_msg);
Log.getLogger().error(err_msg);
return (result, isRemovedItem);
}
int cur_count = 0;
foreach(var category_cart_items in cart_attribute.CartItems.Values)
{
if (category_cart_items.TryGetValue((META_ID)del_cart_item.ItemId, out cur_count) == false)
continue;
if (del_cart_item.Count > cur_count)
{
err_msg = $"Argument count is bigger then cart Item count. cur_count : {cur_count}, req_buy_count : {del_cart_item.Count}";
result.setFail(ServerErrorCode.CartStackCountNotEnough, err_msg);
Log.getLogger().error(err_msg);
return (result, isRemovedItem);
}
category_cart_items[(META_ID)del_cart_item.ItemId] = cur_count - del_cart_item.Count;
if (cur_count - del_cart_item.Count == 0)
{
category_cart_items.Remove((META_ID)del_cart_item.ItemId);
isRemovedItem = true;
}
break;
}
if(cur_count == 0)
{
err_msg = $"Not found itemid from category_cart_items. itemId : {del_cart_item.ItemId}";
result.setFail(ServerErrorCode.CartItemNotFound, err_msg);
Log.getLogger().error(err_msg);
return (result, isRemovedItem);
}
}
cart_attribute.modifiedEntityAttribute();
return (result, isRemovedItem);
}
private async Task<Result> PayCurrencyForItem(List<CartItemInfo> buy_cart_items)
{
var result = new Result();
var my_shop_product = getOwner();
var player = my_shop_product.getRootParent() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var money_action = player.getEntityAction<MoneyAction>();
if (null == money_action)
{
var err_msg = $"Fail to get Money Action : {nameof(MoneyAction)}.";
result.setFail(ServerErrorCode.EntityActionNotFound, err_msg);
Log.getLogger().error(err_msg);
return result;
}
Dictionary<CurrencyType, double> changeMoneys = new Dictionary<CurrencyType, double>();
foreach(var buy_item in buy_cart_items)
{
if(MetaData.Instance._ItemTable.TryGetValue(buy_item.ItemId, out var item_data) == false)
{
var err_msg = $"Not Found ItemDataTable Item Id : {buy_item.ItemId}";
result.setFail(ServerErrorCode.CartMetaDataNotFound, err_msg);
Log.getLogger().error(err_msg);
return result;
}
result = player.checkItemFirstPurchaseItemCount(buy_item.ItemId, buy_item.Count);
if (result.isFail()) return result;
var check_currency_type = ShopHelper.checkCurrencyTypeFromCurrencyId(item_data.Buy_id);
if (check_currency_type.result.isFail()) return check_currency_type.result;
if (changeMoneys.TryGetValue(check_currency_type.currencyType, out var price) == false)
{
changeMoneys.Add(check_currency_type.currencyType, 0);
}
var item_first_purchase_history_agent_action = player.getEntityAction<ItemFirstPurchaseHistoryAgentAction>();
NullReferenceCheckHelper.throwIfNull(item_first_purchase_history_agent_action, () => $"item_first_purchase_history_agent_action is null !!!");
var item_price = item_data.BuyPrice;
if (item_first_purchase_history_agent_action.isItemFirstPurchase(buy_item.ItemId))
{
item_price = ((item_data.BuyPrice * 100) - (item_data.BuyPrice * item_data.Buy_Discount_Rate)) / 100;
}
changeMoneys[check_currency_type.currencyType] += (-1 * item_price * buy_item.Count);
}
foreach(var changeMoney in changeMoneys)
{
result = await money_action.changeMoney(changeMoney.Key, changeMoney.Value);
if (result.isFail()) return result;
}
return result;
}
private async Task<(Result result, List<Item>? changed_Items)> TakeCartItem(List<CartItemInfo> buy_cart_items)
{
var result = new Result();
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var inventory_action = player.getEntityAction<InventoryActionBase>();
if (null == inventory_action)
{
var err_msg = $"Fail to get Inventory Action : {nameof(InventoryActionBase)}.";
result.setFail(ServerErrorCode.EntityActionNotFound, err_msg);
Log.getLogger().error(err_msg);
return (result, null);
}
List<Item> buy_changed_items = new List<Item>();
foreach(var buy_item in buy_cart_items)
{
(result, var changed_items) = await inventory_action.tryTakalbleToBag((META_ID)buy_item.ItemId, (ushort)buy_item.Count);
if (result.isFail()) return (result, null);
buy_changed_items.AddRange(changed_items);
}
return (result, buy_changed_items);
}
public Cart getCart()
{
NullReferenceCheckHelper.throwIfNull(m_Cart, () => $"m_Cart is null !!!");
return m_Cart;
}
async Task<Result> updateItemFirstPurchaseHistory(List<CartItemInfo> buy_cart_items)
{
var result = new Result();
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var item_first_purchase_history_agent_action = player.getEntityAction<ItemFirstPurchaseHistoryAgentAction>();
NullReferenceCheckHelper.throwIfNull(item_first_purchase_history_agent_action, () => $"item_first_purchase_history_agent_action is null !!!");
foreach (var buy_item in buy_cart_items)
{
if (!item_first_purchase_history_agent_action.isItemFirstPurchase(buy_item.ItemId))
continue;
result = await item_first_purchase_history_agent_action.tryAddItemFirstPurchaseHistoryFromMetaId(buy_item.ItemId);
if (result.isFail())
{
return result;
}
}
return result;
}
}