Files
caliverse_server/GameServer/Contents/BeaconShop/Action/BeaconShopAction.cs
2025-05-01 07:20:41 +09:00

1315 lines
64 KiB
C#

using System.Globalization;
using System.Collections.Concurrent;
using Amazon.DynamoDBv2.Model;
using ServerCore;
using ServerBase;
using ServerCommon;
using META_ID = System.UInt32;
using BEACON_GUID = System.String;
using ITEM_GUID = System.String;
using USER_GUID = System.String;
namespace GameServer;
public class BeaconShopAction : EntityActionBase
{
private BeaconShopRepository m_beacon_shop_repository;
private ConcurrentDictionary<BEACON_GUID, List<BeaconShopSoldRecord>> m_beacon_shop_sold_records = new();
private ConcurrentDictionary<BEACON_GUID, BeaconShopSoldPrice> m_beacon_shop_sold_price = new();
private bool m_isUpdateSold = false;
public BeaconShopAction(Player owner)
: base(owner)
{
var server_logic = GameServerApp.getServerLogic();
m_beacon_shop_repository = new BeaconShopRepository( server_logic.getMongoDbConnector().getMongoClient()
, server_logic.getServerConfig().MongoDbConfig );
}
public override Task<Result> onInit()
{
var result = new Result();
return Task.FromResult(result);
}
public override void onClear()
{
m_beacon_shop_sold_records.Clear();
m_beacon_shop_sold_price.Clear();
}
public void setUpdateSoldRecord()
{
m_isUpdateSold = true;
}
private bool checkDailyRegisterCount(UgcNpc ugcNpc)
{
var beacon_shop_profile_attribute = ugcNpc.getOriginEntityAttribute<BeaconShopProfileAttribute>();
NullReferenceCheckHelper.throwIfNull(beacon_shop_profile_attribute, () => $"beacon_shop_profile_attribute is null !!! - {ugcNpc.toBasicString()}");
if (beacon_shop_profile_attribute.RegisterUpdateDay < DateTime.UtcNow.Date.AddHours(ServerCommon.MetaHelper.GameConfigMeta.BeaconShopDailyRegistrationResetTime))
{
return true;
}
return false;
}
private void updateDailyRegisterCount(BeaconShopProfileAttribute beacon_shop_profile_attribute)
{
if (beacon_shop_profile_attribute.RegisterUpdateDay < DateTime.UtcNow.Date.AddHours(ServerCommon.MetaHelper.GameConfigMeta.BeaconShopDailyRegistrationResetTime))
{
beacon_shop_profile_attribute.DailyRegisterCount = 0;
beacon_shop_profile_attribute.RegisterUpdateDay = DateTime.UtcNow.Date.AddHours(ServerCommon.MetaHelper.GameConfigMeta.BeaconShopDailyRegistrationResetTime);
beacon_shop_profile_attribute.modifiedEntityAttribute(true);
}
}
public bool hasBeaconShopSoldRecord(BEACON_GUID beaconGuid)
{
return m_beacon_shop_sold_records.TryGetValue(beaconGuid, out var record);
}
public async Task<Result> AddBeaconShopSoldRecordsFromDocs(List<BeaconShopSoldRecordDoc> beaconShopSoldRecordDocs)
{
var result = new Result();
var err_msg = string.Empty;
m_beacon_shop_sold_records.Clear();
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
foreach (var beacon_shop_sold_record_doc in beaconShopSoldRecordDocs)
{
var beacon_shop_record_attrib = beacon_shop_sold_record_doc.getAttrib<BeaconShopSoldRecordAttrib>();
NullReferenceCheckHelper.throwIfNull(beacon_shop_record_attrib, () => $"beacon_shop_record_attrib is null !!!");
if (m_beacon_shop_sold_records.TryGetValue(beacon_shop_record_attrib.BeaconGuid, out var beacon_shop_sold_record_list) == false)
{
beacon_shop_sold_record_list = new List<BeaconShopSoldRecord>();
if (m_beacon_shop_sold_records.TryAdd(beacon_shop_record_attrib.BeaconGuid, beacon_shop_sold_record_list) == false)
{
err_msg = $"Failed to add beacon_shop_sold_record attribute : {nameof(BeaconShopSoldRecordAttribute)}";
result.setFail(ServerErrorCode.EntityAttributeIsNull, err_msg);
Log.getLogger().error(result.toBasicString());
return result;
}
}
(result, var beacon_shop_sold_record) = await BeaconShopSoldRecord.createBeaconShopSoldRecordFromDoc(player, beacon_shop_sold_record_doc);
if (beacon_shop_sold_record is null)
{
err_msg = $"Failed to create beacon_shop_sold_record from doc";
Log.getLogger().error(err_msg);
continue;
}
beacon_shop_sold_record_list.Add(beacon_shop_sold_record);
}
return result;
}
public async Task<Result> AddBeaconShopSoldPriceFromDocs(List<BeaconShopSoldPriceDoc> beaconShopSoldPriceDocs)
{
var result = new Result();
var err_msg = string.Empty;
m_beacon_shop_sold_price.Clear();
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
foreach (var beacon_shop_sold_price_doc in beaconShopSoldPriceDocs)
{
var beacon_shop_price_attrib = beacon_shop_sold_price_doc.getAttrib<BeaconShopSoldPriceAttrib>();
NullReferenceCheckHelper.throwIfNull(beacon_shop_price_attrib, () => $"beacon_shop_price_attrib is null !!!");
(result, var beacon_shop_sold_price) = await BeaconShopSoldPrice.createBeaconShopSoldPriceFromDoc(player, beacon_shop_sold_price_doc);
if (beacon_shop_sold_price is null)
{
err_msg = $"Failed to create beacon shop sold price from doc";
Log.getLogger().error(err_msg);
return result;
}
m_beacon_shop_sold_price[beacon_shop_price_attrib.BeaconGuid] = beacon_shop_sold_price;
}
return result;
}
public async Task<Result> tryRegisterItemToBeaconShop(ITEM_GUID itemGuid, UInt16 itemAmount, double SellingPrice, BEACON_GUID BeaconGuid)
{
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 !!! - {player.toBasicString()}");
var player_action = player.getEntityAction<PlayerAction>();
var ugc_npc = player_action.findUgcNpc(BeaconGuid);
if (null == ugc_npc)
{
err_msg = $"Not found Beacon !!! : BeaconGuid:{BeaconGuid} - {player.toBasicString()}";
result.setFail(ServerErrorCode.UgcNpcNotFound, err_msg);
return result;
}
(result, META_ID item_meta_id, double req_money) = checkRegisterItemToBeaconShop(itemGuid, itemAmount, SellingPrice, ugc_npc);
if (result.isFail())
{
return result;
}
var fn_start_register_beacon_shop_item = async delegate ()
{
var result = new Result();
var err_msg = string.Empty;
var invokers = new List<ILogInvoker>();
var selling_finish_time = DateTime.UtcNow.AddHours(ServerCommon.MetaHelper.GameConfigMeta.BeaconShopSellPeriod);
var ugc_npc = player_action.findUgcNpc(BeaconGuid);
if (null == ugc_npc)
{
err_msg = $"Not found Beacon !!! : BeaconGuid:{BeaconGuid} - {player.toBasicString()}";
result.setFail(ServerErrorCode.UgcNpcNotFound, err_msg);
return result;
}
var beacon_attribute = ugc_npc.getEntityAttribute<UgcNpcAttribute>();
NullReferenceCheckHelper.throwIfNull(beacon_attribute, () => $"beacon_attribute is null !!!");
var ugc_npc_beacon_shop_action = ugc_npc.getEntityAction<UgcNpcBeaconShopAction>();
//1. 일일 등록 횟수 등록
var beacon_shop_profile_attribute = ugc_npc.getEntityAttribute<BeaconShopProfileAttribute>();
NullReferenceCheckHelper.throwIfNull(beacon_shop_profile_attribute, () => $"beacon_shop_profile_attribute is null !!!");
updateDailyRegisterCount(beacon_shop_profile_attribute);
beacon_shop_profile_attribute.DailyRegisterCount += 1;
beacon_shop_profile_attribute.modifiedEntityAttribute();
//2. 아이템 제거
var inventory_action = player.getEntityAction<InventoryActionBase>();
(result, var changed_item) = await inventory_action.tryDeleteItemByGuid(itemGuid, itemAmount);
if(result.isFail() || changed_item == null)
{
if (result.isSuccess())
result.setFail(ServerErrorCode.BeaconShopException, err_msg);
err_msg = $"Failed to delete Item !!! : itemGuid:{itemGuid}, itemAmount:{itemAmount}, itemMetaId:{item_meta_id} - {player.toBasicString()}";
PacketHandler.BeaconShopRegisterItemPacketHandler.send_S2C_ACK_BEACON_SHOP_REGISTER_ITEM(player, result, null);
return result;
}
var new_item_attribute = changed_item.getEntityAttribute<ItemAttributeBase>();
NullReferenceCheckHelper.throwIfNull(new_item_attribute, () => $"new_item_attribute is null !!!");
//3. 비컨샵 데이터 생성
(result, var beacon_shop_item) = await BeaconShopItem.createBeaconShop(ugc_npc, player.getUserGuid(), BeaconGuid, selling_finish_time, SellingPrice, itemAmount, new_item_attribute);
if (result.isFail() || beacon_shop_item == null)
{
if (result.isSuccess())
result.setFail(ServerErrorCode.BeaconShopException, err_msg);
err_msg = $"Failed to create BeaconShopItem !!! : BeaconGuid:{BeaconGuid} - {player.toBasicString()}";
PacketHandler.BeaconShopRegisterItemPacketHandler.send_S2C_ACK_BEACON_SHOP_REGISTER_ITEM(player, result, null);
return result;
}
var beacon_shop_attribute = beacon_shop_item.getEntityAttribute<BeaconShopItemAttribute>();
NullReferenceCheckHelper.throwIfNull(beacon_shop_attribute, () => $"beacon_shop_attribute is null !!!");
//4. 등록 수수료 차감
var money_action = player.getEntityAction<MoneyAction>();
var item_meta_data = changed_item.getItemMeta();
NullReferenceCheckHelper.throwIfNull(item_meta_data, () => $"item_meta_data is null !!!");
result = await money_action.spendMoney(CurrencyType.Gold, req_money);
if (result.isFail())
{
err_msg = $"Not enough register gold !!! : reqGold:{req_money}, itemGuid:{itemGuid}, reqUnitGoldFee:{item_meta_data.BeaconShopGoldFee} * count:{itemAmount} - {player.toBasicString()}";
PacketHandler.BeaconShopRegisterItemPacketHandler.send_S2C_ACK_BEACON_SHOP_REGISTER_ITEM(player, result, null);
return result;
}
//5. mongo에 등록 (아이템 검색용도)
var beaconShopMongoDoc = new BeaconShopMongoDoc()
{
ItemGuid = beacon_shop_attribute.ItemGuid,
TagId = (int)beacon_shop_attribute.ItemMetaId,
BeaconGuid = beacon_attribute.UgcNpcMetaGuid,
BeaconNickName = beacon_attribute.Nickname,
BeaconTitle = beacon_attribute.Title,
BeaconBodyItemMetaId = (int)beacon_attribute.BodyItemMetaId,
PriceForUnit = SellingPrice,
Amount = beacon_shop_attribute.ItemStackCount,
OwnerGuid = player.getUserGuid(),
OwnerNickName = player.getUserNickname(),
BeaconMyHomeGuid = beacon_attribute.LocatedInstanceGuid,
SellingFinishTime = selling_finish_time,
};
// 6. BeaconShopSoldPriceDoc이 존재하는 지 체크하고, 없으면 생성 한다 !!!
var sold_price_doc = new BeaconShopSoldPriceDoc(player.getUserGuid(), beacon_attribute.UgcNpcMetaGuid);
result = await sold_price_doc.newDoc4Query();
if (result.isFail()) { return result; }
result = await server_logic.getDynamoDbClient().createIfNotExist<BeaconShopSoldPriceDoc>(sold_price_doc
, (sold_price_doc) =>
{
var sold_price_attrib = sold_price_doc.getAttrib<BeaconShopSoldPriceAttrib>();
NullReferenceCheckHelper.throwIfNull(sold_price_attrib, () => $"sold_price_attrib is null !!! - {player.toBasicString()}");
sold_price_attrib.UserGuid = player.getUserGuid();
sold_price_attrib.BeaconGuid = beacon_attribute.UgcNpcMetaGuid;
sold_price_attrib.GivenPrice = 0;
sold_price_attrib.TaxPrice = 0;
}
);
if (result.isFail()) { return result; }
var task_log_data = BeaconShopBusinessLogHelper.toLogInfo(beaconShopMongoDoc);
invokers.Add(new BeaconShopBusinessLog(task_log_data));
result = await m_beacon_shop_repository.insert(beaconShopMongoDoc);
if (result.isFail())
{
err_msg = $"Failed to create BeaconShopItem !!! : BeaconGuid:{BeaconGuid} - {player.toBasicString()}";
PacketHandler.BeaconShopRegisterItemPacketHandler.send_S2C_ACK_BEACON_SHOP_REGISTER_ITEM(player, result, null);
return result;
}
var batch = new QueryBatchEx<QueryRunnerWithDocument>( player, LogActionType.BeaconShopRegisterItem
, server_logic.getDynamoDbClient(), true );
{
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
}
batch.appendBusinessLogs(invokers);
result = await QueryHelper.sendQueryAndBusinessLog(batch);
if (result.isFail())
{
PacketHandler.BeaconShopRegisterItemPacketHandler.send_S2C_ACK_BEACON_SHOP_REGISTER_ITEM(player, result, null);
return result;
}
ugc_npc_beacon_shop_action.addBeaconShopItem(beacon_shop_attribute.ItemGuid, beacon_shop_item);
var found_transaction_runner = player.findTransactionRunner(TransactionIdType.PrivateContents);
if (null == found_transaction_runner)
{
err_msg = $"Not found TransactionRunner !!! : {toBasicString()} - {player.toBasicString()}";
Log.getLogger().warn(err_msg);
PacketHandler.BeaconShopReturnItemPacketHandler.send_S2C_ACK_BEACON_SHOP_RETURN_ITEM(player, result);
return result;
}
BeaconShopHelper.send_GS2GS_NTF_UPDATE_BEACON_SHOP_ITEM(player.getUserGuid(), BeaconGuid);
PacketHandler.BeaconShopRegisterItemPacketHandler.send_S2C_ACK_BEACON_SHOP_REGISTER_ITEM(player, result, beacon_shop_item, found_transaction_runner.getCommonResult());
return result;
};
result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "RegisterItemToBeaconShop", fn_start_register_beacon_shop_item);
if (result.isFail())
{
err_msg = $"Failed to runTransactionRunnerSafely() !!! : {result.toBasicString()} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
}
return result;
}
public async Task<Result> BeaconShopReturnItem(ITEM_GUID itemGuid, BEACON_GUID beaconGuid)
{
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 !!! - {player.toBasicString()}");
(result, var found_ugc_npc, var ugc_npc_owner) = await NpcHelper.findUgcNpc(beaconGuid, player.getUserGuid());
if (found_ugc_npc == null)
{
if (result.isSuccess())
result.setFail(ServerErrorCode.UgcNpcNotFound, err_msg);
err_msg = $"Not found Beacon !!! : itemGuid:{itemGuid} beaconOwner:{player.getUserGuid()} - {player.toBasicString()}";
return result;
}
var fn_start_return_item = async delegate ()
{
using (var runner_with_scope = new EntityTransactionRunnerWithScopLock(found_ugc_npc))
{
result = await runner_with_scope.tryInvokeWithAsyncLock(() => BeaconShopReturnItemUpdate(itemGuid, beaconGuid));
if (result.isFail())
{
return result;
}
Log.getLogger().debug($"Successed tryInvokeWithAsyncLock BeaconShopReturnItemUpdate - {found_ugc_npc.toBasicString()}");
}
return result;
};
result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "ReturnItemFromBeaconShop", fn_start_return_item);
if (result.isFail())
{
err_msg = $"Failed to runTransactionRunnerSafely() !!! : {result.toBasicString()} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
}
return result;
}
private async Task<Result> BeaconShopReturnItemUpdate(ITEM_GUID itemGuid, BEACON_GUID beaconGuid)
{
var result = new Result();
var err_msg = string.Empty;
var invokers = new List<ILogInvoker>();
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var server_logic = GameServerApp.getServerLogic();
NullReferenceCheckHelper.throwIfNull(server_logic, () => $"server_logic is null !!! - {player.toBasicString()}");
var player_action = player.getEntityAction<PlayerAction>();
var ugc_npc = player_action.findUgcNpc(beaconGuid);
if (null == ugc_npc)
{
err_msg = $"Not found Beacon !!! : BeaconGuid:{beaconGuid} - {player.toBasicString()}";
result.setFail(ServerErrorCode.UgcNpcNotFound, err_msg);
PacketHandler.BeaconShopReturnItemPacketHandler.send_S2C_ACK_BEACON_SHOP_RETURN_ITEM(player, result);
return result;
}
var beacon_attribute = ugc_npc.getEntityAttribute<UgcNpcAttribute>();
NullReferenceCheckHelper.throwIfNull(beacon_attribute, () => $"beacon_attribute is null !!!");
var ugc_npc_beacon_shop_action = ugc_npc.getEntityAction<UgcNpcBeaconShopAction>();
//1. 아이템 찾기
var found_item = ugc_npc_beacon_shop_action.getBeaconShopItem(itemGuid);
if (found_item == null)
{
err_msg = $"Failed to tryGetItemByItemGuid BeaconShopItem !!! : itemGuid : {itemGuid}, {player.toBasicString()}";
result.setFail(ServerErrorCode.ItemNotFound, err_msg);
PacketHandler.BeaconShopReturnItemPacketHandler.send_S2C_ACK_BEACON_SHOP_RETURN_ITEM(player, result);
return result;
}
//2. 지급할 아이템 복사 & Guid 생성
var cloned_beacon_item_attribute = found_item.getClonedEntityAttribute<BeaconShopItemAttribute>();
NullReferenceCheckHelper.throwIfNull(cloned_beacon_item_attribute, () => $"cloned_beacon_item_attribute is null !!!");
(result, var item_doc) = await cloned_beacon_item_attribute.toDocBase(false);
NullReferenceCheckHelper.throwIfNull(item_doc, () => $"item_doc is null !!!");
var beacon_shop_item_doc = item_doc as BeaconShopItemDoc;
NullReferenceCheckHelper.throwIfNull(beacon_shop_item_doc, () => $"beacon_shop_item_doc is null !!!");
var new_item_doc = BeaconShopHelper.toItemDocFromBeaconShopItemDoc(beacon_shop_item_doc, cloned_beacon_item_attribute.ItemStackCount);
//3. Inventory로 아이템 지급
var inventory_action = player.getEntityAction<InventoryActionBase>();
(result, var new_items) = await inventory_action.tryTakableToBagWithNewItem(new_item_doc);
if (result.isFail() || new_items == null)
{
if (result.isSuccess())
result.setFail(ServerErrorCode.BeaconShopException, err_msg);
err_msg = $"Failed to tryTakableToBagWithNewItem !!! : itemGuid:{itemGuid} - {player.toBasicString()}";
PacketHandler.BeaconShopReturnItemPacketHandler.send_S2C_ACK_BEACON_SHOP_RETURN_ITEM(player, result);
return result;
}
//4. mongo에서 제거
await m_beacon_shop_repository.delete(itemGuid);
var task_log_data = BeaconShopBusinessLogHelper.toLogInfo(cloned_beacon_item_attribute, beacon_attribute, player.getUserGuid());
invokers.Add(new BeaconShopBusinessLog(task_log_data));
var batch = new QueryBatchEx<QueryRunnerWithItemRequest>( player, LogActionType.BeaconShopReturnItem
, server_logic.getDynamoDbClient(), true);
{
batch.addQuery(new DBQBeaconShopItemDelete(beaconGuid, itemGuid, cloned_beacon_item_attribute.ItemStackCount));
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
}
batch.appendBusinessLogs(invokers);
result = await QueryHelper.sendQueryAndBusinessLog(batch);
if (result.isFail())
{
PacketHandler.BeaconShopReturnItemPacketHandler.send_S2C_ACK_BEACON_SHOP_RETURN_ITEM(player, result);
ugc_npc_beacon_shop_action.setUpdateBeaconShopItem();
player.send_S2C_NTF_BEACON_SHOP_REFRESH(beaconGuid);
return result;
}
ugc_npc_beacon_shop_action.removeBeaconShopItem(itemGuid);
var found_transaction_runner = player.findTransactionRunner(TransactionIdType.PrivateContents);
if (null == found_transaction_runner)
{
err_msg = $"Not found TransactionRunner !!! : {toBasicString()} - {player.toBasicString()}";
Log.getLogger().warn(err_msg);
PacketHandler.BeaconShopReturnItemPacketHandler.send_S2C_ACK_BEACON_SHOP_RETURN_ITEM(player, result);
return result;
}
PacketHandler.BeaconShopReturnItemPacketHandler.send_S2C_ACK_BEACON_SHOP_RETURN_ITEM(player, result, itemGuid, beaconGuid, found_transaction_runner.getCommonResult());
return result;
}
public async Task<Result> BeaconShopPurchaseItem(ITEM_GUID itemGuid, UInt16 itemAmount, BEACON_GUID beaconGuid, USER_GUID beaconOwnerGuid)
{
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 !!! - {player.toBasicString()}");
(result, var found_ugc_npc, var ugc_npc_owner) = await NpcHelper.findUgcNpc(beaconGuid, beaconOwnerGuid);
if (found_ugc_npc == null)
{
if (result.isSuccess())
result.setFail(ServerErrorCode.UgcNpcNotFound, err_msg);
err_msg = $"Not found Beacon !!! : itemGuid:{itemGuid} beaconOwner:{beaconOwnerGuid} - {player.toBasicString()}";
return result;
}
var fn_start_purchase_item = async delegate ()
{
var result = new Result();
var err_msg = string.Empty;
using (var runner_with_scope = new EntityTransactionRunnerWithScopLock(found_ugc_npc))
{
result = await runner_with_scope.tryInvokeWithAsyncLock(() => BeaconShopItemPurchaseUpdate(itemGuid, itemAmount, beaconGuid, beaconOwnerGuid));
if (result.isFail())
{
return result;
}
Log.getLogger().debug($"Successed tryInvokeWithAsyncLock BeaconShopItemPurchaseUpdate - {found_ugc_npc.toBasicString()}");
}
return result;
};
result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "PurchaseBeaconShopItem", fn_start_purchase_item);
if (result.isFail())
{
err_msg = $"Failed to runTransactionRunnerSafely() !!! : {result.toBasicString()} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
}
return result;
}
private async Task<Result> BeaconShopItemPurchaseUpdate(ITEM_GUID itemGuid, UInt16 itemAmount, BEACON_GUID beaconGuid, USER_GUID beaconOwnerGuid)
{
var result = new Result();
var err_msg = string.Empty;
var server_logic = GameServerApp.getServerLogic();
var invokers = new List<ILogInvoker>();
var dbClient = server_logic.getDynamoDbClient();
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
// 1. 아이템 갯수 확인
(result, var found_ugc_npc, var ugc_npc_owner) = await NpcHelper.findUgcNpc(beaconGuid, beaconOwnerGuid);
if (found_ugc_npc == null)
{
if (result.isSuccess())
result.setFail(ServerErrorCode.UgcNpcNotFound, err_msg);
err_msg = $"Not found Beacon !!! : itemGuid:{itemGuid} beaconOwner:{beaconOwnerGuid} - {player.toBasicString()}";
PacketHandler.BeaconShopPurchaseItemPacketHandler.send_S2C_ACK_BEACON_SHOP_PURCHASE_ITEM(player, result);
return result;
}
var ugc_npc_attribute = found_ugc_npc.getEntityAttribute<UgcNpcAttribute>();
NullReferenceCheckHelper.throwIfNull(ugc_npc_attribute, () => $"ugc_npc_attribute is null !!! - {player.toBasicString()}");
USER_GUID beacon_owner_guid = ugc_npc_attribute.OwnerGuid;
var ugc_npc_beacon_shop_action = found_ugc_npc.getEntityAction<UgcNpcBeaconShopAction>();
var beacon_shop_item = ugc_npc_beacon_shop_action.getBeaconShopItem(itemGuid);
if (beacon_shop_item == null)
{
err_msg = $"Not found Beacon Shop Item !!! : itemGuid:{itemGuid} beaconOwner:{beaconOwnerGuid} - {player.toBasicString()}";
result.setFail(ServerErrorCode.BeaconShopLackOfItemAmount, err_msg);
PacketHandler.BeaconShopPurchaseItemPacketHandler.send_S2C_ACK_BEACON_SHOP_PURCHASE_ITEM(player, result);
return result;
}
var beacon_shop_item_attribute = beacon_shop_item.getEntityAttribute<BeaconShopItemAttribute>();
NullReferenceCheckHelper.throwIfNull(beacon_shop_item_attribute, () => $"beacon_shop_item_attribute is null !!! - {player.toBasicString()}");
int left_item_stack_count = beacon_shop_item_attribute.ItemStackCount - itemAmount;
if (left_item_stack_count < 0)
{
err_msg = $"Item is already sold out !!! : itemGuid:{itemGuid} beaconOwner:{beaconOwnerGuid} - {player.toBasicString()}";
result.setFail(ServerErrorCode.BeaconShopLackOfItemAmount, err_msg);
PacketHandler.BeaconShopPurchaseItemPacketHandler.send_S2C_ACK_BEACON_SHOP_PURCHASE_ITEM(player, result);
return result;
}
// 2. 판매 시간 확인
if(beacon_shop_item_attribute.SellingFinishTime <= DateTime.UtcNow)
{
err_msg = $"Item selling time is over !!! : finishTime:{beacon_shop_item_attribute.SellingFinishTime}, itemGuid:{itemGuid} beaconOwner:{beaconOwnerGuid} - {player.toBasicString()}";
result.setFail(ServerErrorCode.BeaconShopLackOfItemAmount, err_msg);
PacketHandler.BeaconShopPurchaseItemPacketHandler.send_S2C_ACK_BEACON_SHOP_PURCHASE_ITEM(player, result);
return result;
}
// 3. 비용 차감
var money_action = player.getEntityAction<MoneyAction>();
result = await money_action.changeMoney(CurrencyType.Calium, -1 * beacon_shop_item_attribute.PriceForUnit * itemAmount);
if (result.isFail())
{
err_msg = $"Not enough calium !!! : itemGuid:{itemGuid}, need Calium fee : {beacon_shop_item_attribute.PriceForUnit * itemAmount} - {player.toBasicString()}";
PacketHandler.BeaconShopPurchaseItemPacketHandler.send_S2C_ACK_BEACON_SHOP_PURCHASE_ITEM(player, result);
return result;
}
// 4. 지급할 아이템 복사 & Guid 생성& 갯수 변경
var cloned_beacon_item_attribute = beacon_shop_item.getClonedEntityAttribute<BeaconShopItemAttribute>();
NullReferenceCheckHelper.throwIfNull(cloned_beacon_item_attribute, () => $"cloned_beacon_item_attribute is null !!!");
(result, var item_doc) = await cloned_beacon_item_attribute.toDocBase(false);
NullReferenceCheckHelper.throwIfNull(item_doc, () => $"item_doc is null !!!");
var beacon_shop_item_doc = item_doc as BeaconShopItemDoc;
NullReferenceCheckHelper.throwIfNull(beacon_shop_item_doc, () => $"beacon_shop_item_doc is null !!!");
var beacon_shop_item_attrib = beacon_shop_item_doc.getAttrib<BeaconShopItemAttrib>();
NullReferenceCheckHelper.throwIfNull(beacon_shop_item_attrib, () => $"beacon_shop_item_attrib is null !!!");
var new_item_doc = BeaconShopHelper.toItemDocFromBeaconShopItemDoc(beacon_shop_item_doc, itemAmount);
// 5. 아이템 지급
var inventory_action = player.getEntityAction<InventoryActionBase>();
(result, var new_items) = await inventory_action.tryTakableToBagWithNewItem(new_item_doc);
if (result.isFail() || new_items == null)
{
if (result.isSuccess())
result.setFail(ServerErrorCode.BeaconShopException, err_msg);
err_msg = $"Failed to tryTakableToBagWithNewItem !!! : itemGuid:{itemGuid} - {player.toBasicString()}";
PacketHandler.BeaconShopPurchaseItemPacketHandler.send_S2C_ACK_BEACON_SHOP_PURCHASE_ITEM(player, result);
return result;
}
// 6. 칼리움 판매금 계산
double sold_price = CaliumStorageHelper.MultiplyDoubleByLong(beacon_shop_item_attribute.PriceForUnit, (double)itemAmount);
double tax_price = Math.Ceiling(ServerCommon.MetaHelper.GameConfigMeta.BeaconShopSellFee * 100 * sold_price) / 100;
double given_price = CaliumStorageHelper.SubTractDoubleByLong(sold_price, tax_price);
// 7. 구매 기록 남김
var beacon_shop_item_history_doc = await BeaconShopHelper.CreateBeaconShopSoldRecord(beacon_shop_item_attribute, player.getUserNickname(), itemAmount, sold_price, tax_price, given_price);
if(beacon_shop_item_history_doc == null)
{
result.setFail(ServerErrorCode.BeaconShopException, err_msg);
err_msg = $"Failed to Create CreateBeaconShopSoldRecord doc !!! : itemGuid:{itemGuid} - {player.toBasicString()}";
PacketHandler.BeaconShopPurchaseItemPacketHandler.send_S2C_ACK_BEACON_SHOP_PURCHASE_ITEM(player, result);
return result;
}
// 8. mongo에 업데이트
(result, var beacon_shop_mongo_doc) = await m_beacon_shop_repository.updateAmount(itemGuid, -1 * itemAmount);
if (result.isFail() || beacon_shop_mongo_doc == null)
{
if (result.isSuccess())
result.setFail(ServerErrorCode.BeaconShopException, err_msg);
err_msg = $"Failed to delete BeaconShopItem !!! : ItemGuid:{itemGuid}, BeaconGuid:{beaconGuid} - {player.toBasicString()}";
PacketHandler.BeaconShopPurchaseItemPacketHandler.send_S2C_ACK_BEACON_SHOP_PURCHASE_ITEM(player, result);
return result;
}
// 9. BeaconShopSoldPriceUpdate
(result, var query_context) = BeaconShopSoldPriceUpdate(beacon_owner_guid, beaconGuid, given_price, tax_price, 1);
if (result.isFail() || query_context == null)
{
if (result.isSuccess())
result.setFail(ServerErrorCode.BeaconShopException, err_msg);
err_msg = $"Failed to BeaconShopSoldPriceUpdate !!! : OwnerGuid:{beacon_owner_guid}, ItemGuid:{itemGuid}, BeaconGuid:{beaconGuid}, GibenPrice:{given_price}, TaxPrice:{tax_price} - {player.toBasicString()}";
PacketHandler.BeaconShopPurchaseItemPacketHandler.send_S2C_ACK_BEACON_SHOP_PURCHASE_ITEM(player, result);
return result;
}
var task_log_data = BeaconShopBusinessLogHelper.toLogInfo(cloned_beacon_item_attribute, ugc_npc_attribute, player.getUserGuid());
invokers.Add(new BeaconShopBusinessLog(task_log_data));
var task_price_log_data = BeaconShopBusinessLogHelper.toLogInfo(beacon_owner_guid, beaconGuid, given_price, tax_price);
invokers.Add(new BeaconShopSoldPriceBusinessLog(task_price_log_data));
var batch = new QueryBatchEx<QueryRunnerWithItemRequest>( player, LogActionType.BeaconShopPurchaseItem
, dbClient
, true);
{
batch.addQuery(new DBQEntityWrite(beacon_shop_item_history_doc));
batch.addQuery(new DBQBeaconShopItemUpdate(beaconGuid, itemGuid, -1 * itemAmount));
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
batch.addQuery(new DBQWithItemRequestQueryContext(query_context));
}
batch.appendBusinessLogs(invokers);
result = await QueryHelper.sendQueryAndBusinessLog(batch);
if (result.isFail())
{
PacketHandler.BeaconShopReturnItemPacketHandler.send_S2C_ACK_BEACON_SHOP_RETURN_ITEM(player, result);
ugc_npc_beacon_shop_action.setUpdateBeaconShopItem();
player.send_S2C_NTF_BEACON_SHOP_REFRESH(beaconGuid);
return result;
}
var beacon_shop_item_origin_attribute = beacon_shop_item.getOriginEntityAttribute<BeaconShopItemAttribute>();
NullReferenceCheckHelper.throwIfNull(beacon_shop_item_origin_attribute, () => $"beacon_shop_item_origin_attribute is null !!! - {player.toBasicString()}");
beacon_shop_item_origin_attribute.ItemStackCount -= itemAmount;
if(beacon_shop_item_origin_attribute.ItemStackCount == 0)
{
await dbClient.simpleDeleteDocumentWithDocType(beacon_shop_item_doc);
ugc_npc_beacon_shop_action.removeBeaconShopItem(itemGuid);
}
var found_transaction_runner = player.findTransactionRunner(TransactionIdType.PrivateContents);
if (null == found_transaction_runner)
{
err_msg = $"Not found TransactionRunner !!! : {toBasicString()} - {player.toBasicString()}";
Log.getLogger().warn(err_msg);
PacketHandler.BeaconShopReturnItemPacketHandler.send_S2C_ACK_BEACON_SHOP_RETURN_ITEM(player, result);
return result;
}
PacketHandler.BeaconShopPurchaseItemPacketHandler.send_S2C_ACK_BEACON_SHOP_PURCHASE_ITEM(player, result, itemGuid, beaconGuid, left_item_stack_count, found_transaction_runner.getCommonResult());
BeaconShopHelper.send_GS2GS_NTF_UPDATE_BEACON_SHOP_ITEM(beacon_owner_guid, beaconGuid);
var player_manager = server_logic.getPlayerManager();
if (player_manager.tryGetUserByPrimaryKey(beacon_owner_guid, out var found_user) == true)
{
var found_user_beacon_shop_action = found_user.getEntityAction<BeaconShopAction>();
found_user_beacon_shop_action.setUpdateSoldRecord();
}
else
{
var login_cache_request = new LoginCacheOtherUserRequest(player, server_logic.getRedisConnector(), beacon_owner_guid);
await login_cache_request.fetchLogin();
var login_cache = login_cache_request.getLoginCache();
if (login_cache != null)
{
BeaconShopHelper.send_GS2GS_NTF_UPDATE_SOLD_RECORD(login_cache.CurrentServer, beacon_owner_guid);
}
}
return result;
}
private (Result, DynamoDbItemRequestQueryContext?) BeaconShopSoldPriceUpdate(string combinationKeyForPK, string combinationKeyForSK, double givenPrice, double taxPrice, int numOfReceiptNotReceived)
{
var result = new Result();
var err_msg = string.Empty;
var to_change_attrib_actions = new Dictionary<string, DynamoDbItemRequestHelper.AttribAction>();
var givenAttribValueAction = givenPrice > 0 ? DynamoDbItemRequestHelper.AttribValueAction.Increase : DynamoDbItemRequestHelper.AttribValueAction.Decrease;
var taxAttribValueAction = taxPrice > 0 ? DynamoDbItemRequestHelper.AttribValueAction.Increase : DynamoDbItemRequestHelper.AttribValueAction.Decrease;
var numOfReceiptNotReceivedAttribValueAction = numOfReceiptNotReceived > 0 ? DynamoDbItemRequestHelper.AttribValueAction.Increase : DynamoDbItemRequestHelper.AttribValueAction.Decrease;
to_change_attrib_actions.Add(nameof(BeaconShopSoldPriceAttrib.GivenPrice)
, new DynamoDbItemRequestHelper.AttribAction
{
ValueAction = givenAttribValueAction,
Value = new AttributeValue { N = Math.Abs(givenPrice).ToString(CultureInfo.InvariantCulture) }
});
to_change_attrib_actions.Add(nameof(BeaconShopSoldPriceAttrib.TaxPrice)
, new DynamoDbItemRequestHelper.AttribAction
{
ValueAction = taxAttribValueAction,
Value = new AttributeValue { N = Math.Abs(taxPrice).ToString(CultureInfo.InvariantCulture) }
});
to_change_attrib_actions.Add(nameof(BeaconShopSoldPriceAttrib.NumOfReceiptNotReceived)
, new DynamoDbItemRequestHelper.AttribAction
{
ValueAction = numOfReceiptNotReceivedAttribValueAction,
Value = new AttributeValue { N = Math.Abs(numOfReceiptNotReceived).ToString(CultureInfo.InvariantCulture) }
});
var refund_bid_price_doc = new BeaconShopSoldPriceDoc(combinationKeyForPK, combinationKeyForSK);
(result, var query_context) = DynamoDbItemRequestHelper.makeUpdateItemRequestWithDoc<BeaconShopSoldPriceAttrib>(refund_bid_price_doc, to_change_attrib_actions);
if (result.isFail())
{
return (result, null);
}
NullReferenceCheckHelper.throwIfNull(query_context, () => $"query_context is null !!!");
return (result, query_context);
}
public async Task<Result> BeaconShopGetSoldRecords(BEACON_GUID BeaconGuid)
{
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 !!! - {player.toBasicString()}");
result = await updateBeaconShopSold();
if (result.isFail())
{
err_msg = $"Failed to updateBeaconShopSold !!! : {player.toBasicString()}";
Log.getLogger().warn(err_msg);
return result;
}
double total_given_price = 0;
m_beacon_shop_sold_records.TryGetValue(BeaconGuid, out var beacon_shop_sold_record_list);
if(m_beacon_shop_sold_price.TryGetValue(BeaconGuid, out var beacon_shop_sold_price) == true)
{
var beacon_shop_price_attribute = beacon_shop_sold_price.getEntityAttribute<BeaconShopSoldPriceAttribute>();
NullReferenceCheckHelper.throwIfNull(beacon_shop_price_attribute, () => $"beacon_shop_price_attribute is null !!! - {player.toBasicString()}");
total_given_price = beacon_shop_price_attribute.GivenPrice;
}
PacketHandler.BeaconShopSoldRecordInfoPacketHandler.send_S2C_ACK_BEACON_SHOP_GET_SOLD_RECORDS(player, result, beacon_shop_sold_record_list, total_given_price);
return result;
}
public async Task<Result> ProcessBeaconShopDeleteRecord()
{
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_delete_record = async delegate ()
{
var result = new Result();
var invokers = new List<ILogInvoker>();
bool delete_record = false;
var delete_beacon_shop_sold_records = new ConcurrentDictionary<BEACON_GUID, List<BeaconShopSoldRecord>>();
foreach (var beacon_shop_record_list in m_beacon_shop_sold_records.Values)
{
var deleteCount = beacon_shop_record_list.Count - ServerCommon.MetaHelper.GameConfigMeta.BeaconShopPaymentListMaxCount;
if(deleteCount <= 0)
continue;
delete_record = true;
foreach(var beacon_shop_record in beacon_shop_record_list)
{
if(deleteCount <= 0)
break;
deleteCount -= 1;
var beacon_shop_sold_record_attribute = beacon_shop_record.getEntityAttribute<BeaconShopSoldRecordAttribute>();
NullReferenceCheckHelper.throwIfNull(beacon_shop_sold_record_attribute, () => "beacon_shop_sold_record_attribute is null !!!");
beacon_shop_sold_record_attribute.deleteEntityAttribute();
var task_log_data = BeaconShopBusinessLogHelper.toLogInfo(beacon_shop_sold_record_attribute);
invokers.Add(new BeaconShopSoldRecordBusinessLog(task_log_data));
if(delete_beacon_shop_sold_records.TryGetValue(beacon_shop_sold_record_attribute.BeaconGuid, out var deleteBeaconShopSoldRecordList) == false)
{
deleteBeaconShopSoldRecordList = new List<BeaconShopSoldRecord>();
delete_beacon_shop_sold_records[beacon_shop_sold_record_attribute.BeaconGuid] = deleteBeaconShopSoldRecordList;
}
deleteBeaconShopSoldRecordList.Add(beacon_shop_record);
}
}
if(delete_record == false)
{
return result;
}
var batch = new QueryBatchEx<QueryRunnerWithDocument>( player, LogActionType.BeaconShopDeleteRecord
, server_logic.getDynamoDbClient() );
{
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
}
batch.appendBusinessLogs(invokers);
result = await QueryHelper.sendQueryAndBusinessLog(batch);
if (result.isFail())
{
return result;
}
foreach(var delete_beacon_shop_sold_record in delete_beacon_shop_sold_records)
{
if(m_beacon_shop_sold_records.TryGetValue(delete_beacon_shop_sold_record.Key, out var beaconShopSoldRecords) == false)
continue;
foreach(var delete_sold_record in delete_beacon_shop_sold_record.Value)
{
beaconShopSoldRecords.Remove(delete_sold_record);
}
}
return result;
};
result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "BeaconShopDeleteRecord", fn_delete_record);
if (result.isFail())
{
err_msg = $"Failed to runTransactionRunnerSafely()!!! : {result.toBasicString()} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
}
return result;
}
public async Task<Result> BeaconShopReceivePaymentForSales(BEACON_GUID BeaconGuid)
{
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 !!! - {player.toBasicString()}");
var fn_start_beacon_shop_receive_payment_for_sales = async delegate ()
{
var result = new Result();
var err_msg = string.Empty;
var calium_storage_entity = GameServerApp.getServerLogic().findGlobalEntity<CaliumStorageEntity>();
NullReferenceCheckHelper.throwIfNull(calium_storage_entity, () => $"calium_storage_entity is null !!! - {player.toBasicString()}");
var invokers = new List<ILogInvoker>();
if(m_beacon_shop_sold_price.TryGetValue(BeaconGuid, out var beaconShopSoldPrice) == false)
{
err_msg = $"Failed reload Beacon Shop Sold Price !!! : BeaconGuid:{BeaconGuid} - {player.toBasicString()}";
result.setFail(ServerErrorCode.BeaconShopNotFoundSoldPrice, err_msg);
PacketHandler.BeaconShopReceivePaymentForSalesPacketHandler.send_S2C_ACK_BEACON_SHOP_RECEIVE_PAYMENT_FOR_SALES(player, result);
return result;
}
var beacon_shop_sold_price_attribute = beaconShopSoldPrice.getEntityAttribute<BeaconShopSoldPriceAttribute>();
NullReferenceCheckHelper.throwIfNull(beacon_shop_sold_price_attribute, () => $"beacon_shop_sold_price_attribute is null !!! - {player.toBasicString()}");
// 1. 돈 지급
var money_action = player.getEntityAction<MoneyAction>();
result = await money_action.changeMoney(CurrencyType.Calium, beacon_shop_sold_price_attribute.GivenPrice);
if (result.isFail())
{
err_msg = $"Failed to changeMoney !!! : change price delta :{beacon_shop_sold_price_attribute.GivenPrice} - {player.toBasicString()}";
PacketHandler.BeaconShopReceivePaymentForSalesPacketHandler.send_S2C_ACK_BEACON_SHOP_RECEIVE_PAYMENT_FOR_SALES(player, result);
return result;
}
// 2. BeaconShopSoldPriceUpdate
(result, var query_context) = BeaconShopSoldPriceUpdate(beacon_shop_sold_price_attribute.UserGuid, beacon_shop_sold_price_attribute.BeaconGuid, -1 * beacon_shop_sold_price_attribute.GivenPrice, -1 * beacon_shop_sold_price_attribute.TaxPrice, -1 * beacon_shop_sold_price_attribute.NumOfReceiptNotReceived);
if (result.isFail() || query_context == null)
{
if (result.isSuccess())
result.setFail(ServerErrorCode.BeaconShopException, err_msg);
err_msg = $"Failed to BeaconShopSoldPriceUpdate !!! : OwnerGuid:{beacon_shop_sold_price_attribute.UserGuid}, BeaconGuid:{beacon_shop_sold_price_attribute.BeaconGuid}, GibenPrice:{-1 * beacon_shop_sold_price_attribute.GivenPrice}, TaxPrice:{-1 * beacon_shop_sold_price_attribute.TaxPrice} - {player.toBasicString()}";
PacketHandler.BeaconShopPurchaseItemPacketHandler.send_S2C_ACK_BEACON_SHOP_PURCHASE_ITEM(player, result);
return result;
}
var task_price_log_data = BeaconShopBusinessLogHelper.toLogInfo(beacon_shop_sold_price_attribute.UserGuid, beacon_shop_sold_price_attribute.BeaconGuid, -1 * beacon_shop_sold_price_attribute.GivenPrice, -1 * beacon_shop_sold_price_attribute.TaxPrice);
invokers.Add(new BeaconShopSoldPriceBusinessLog(task_price_log_data));
var batch = new QueryBatchEx<QueryRunnerWithItemRequest>( player, LogActionType.BeaconShopReceivePaymentForSales
, server_logic.getDynamoDbClient(), true);
{
batch.addQuery(new DBQWriteToAttributeAllWithTransactionRunner());
batch.addQuery(new DBQWithItemRequestQueryContext(query_context));
}
batch.appendBusinessLogs(invokers);
result = await QueryHelper.sendQueryAndBusinessLog(batch);
if (result.isFail())
{
PacketHandler.BeaconShopReceivePaymentForSalesPacketHandler.send_S2C_ACK_BEACON_SHOP_RECEIVE_PAYMENT_FOR_SALES(player, result);
return result;
}
var found_transaction_runner = player.findTransactionRunner(TransactionIdType.PrivateContents);
if (null == found_transaction_runner)
{
err_msg = $"Not found TransactionRunner !!! : {toBasicString()} - {player.toBasicString()}";
Log.getLogger().warn(err_msg);
PacketHandler.BeaconShopReturnItemPacketHandler.send_S2C_ACK_BEACON_SHOP_RETURN_ITEM(player, result);
return result;
}
// 칼리움 소각
var trans_id = found_transaction_runner.getTransId();
var calium_event_action = calium_storage_entity.getEntityAction<CaliumEventAction>();
NullReferenceCheckHelper.throwIfNull(calium_event_action, () => $"calium_event_action is null !!! - {player.toBasicString()}");
await calium_event_action.sendCaliumBurnEvent(player, trans_id, player.getUserNickname(), LogActionType.BeaconShopReceivePaymentForSales.ToString(), -1 * beacon_shop_sold_price_attribute.TaxPrice);
var beacon_shop_sold_price_origin_attribute = beaconShopSoldPrice.getOriginEntityAttribute<BeaconShopSoldPriceAttribute>();
NullReferenceCheckHelper.throwIfNull(beacon_shop_sold_price_origin_attribute, () => $"beacon_shop_sold_price_origin_attribute is null !!! - {player.toBasicString()}");
beacon_shop_sold_price_origin_attribute.GivenPrice = 0;
beacon_shop_sold_price_origin_attribute.TaxPrice = 0;
beacon_shop_sold_price_origin_attribute.NumOfReceiptNotReceived = 0;
PacketHandler.BeaconShopReceivePaymentForSalesPacketHandler.send_S2C_ACK_BEACON_SHOP_RECEIVE_PAYMENT_FOR_SALES(player, result, BeaconGuid, found_transaction_runner.getCommonResult());
return result;
};
result = await player.runTransactionRunnerSafely(TransactionIdType.PrivateContents, "BeaconShopReceivePaymentForSales", fn_start_beacon_shop_receive_payment_for_sales);
if (result.isFail())
{
err_msg = $"Failed to runTransactionRunnerSafely() !!! : {result.toBasicString()} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
}
return result;
}
public async Task<Result> BeaconShopSearchItem(META_ID item_meta_id)
{
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 !!! - {player.toBasicString()}");
(result, var beacon_shop_mongo_doc_list) = await m_beacon_shop_repository.get((int)item_meta_id);
if(result.isFail() || beacon_shop_mongo_doc_list == null)
{
if (result.isSuccess())
result.setFail(ServerErrorCode.BeaconShopFailedGetBoardItem, err_msg);
PacketHandler.BeaconShopSearchItemPacketHandler.send_S2C_ACK_BEACON_SHOP_SEARCH_ITEM(player, result, null);
return result;
}
PacketHandler.BeaconShopSearchItemPacketHandler.send_S2C_ACK_BEACON_SHOP_SEARCH_ITEM(player, result, beacon_shop_mongo_doc_list);
return result;
}
public async Task<Result> BeaconShopGetItemInfos(BEACON_GUID beaconGuid, USER_GUID beaconOwnerGuid)
{
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 !!! - {player.toBasicString()}");
(result, var found_ugc_npc, var ugc_npc_owner) = await NpcHelper.findUgcNpc(beaconGuid, beaconOwnerGuid);
if (found_ugc_npc == null)
{
err_msg = $"Not found Beacon !!! : beaconGuid:{beaconGuid} beaconOwner:{beaconOwnerGuid} - {player.toBasicString()}";
result.setFail(ServerErrorCode.UgcNpcNotFound, err_msg);
return result;
}
var beacon_shop_profile_attribute = found_ugc_npc.getEntityAttribute<BeaconShopProfileAttribute>();
NullReferenceCheckHelper.throwIfNull(beacon_shop_profile_attribute, () => $"beacon_shop_profile_attribute is null !!!");
await ProcessUpdateDailyRegisterCount(found_ugc_npc);
(result, var beacon_shop_item_reload_data) = await ReloadBeaconShop(beaconGuid, beaconOwnerGuid);
if (result.isFail())
{
return result;
}
result = await updateBeaconShopSold();
if (result.isFail())
{
err_msg = $"Failed to updateBeaconShopSold !!! : {player.toBasicString()}";
Log.getLogger().warn(err_msg);
return result;
}
int numOfReceiptNotReceived = 0;
if (m_beacon_shop_sold_price.TryGetValue(beaconGuid, out var beaconShopSoldPrice) == true)
{
var beacon_shop_sold_price_attribute = beaconShopSoldPrice.getEntityAttribute<BeaconShopSoldPriceAttribute>();
NullReferenceCheckHelper.throwIfNull(beacon_shop_sold_price_attribute, () => $"beacon_shop_sold_price_attribute is null !!! - {player.toBasicString()}");
numOfReceiptNotReceived = beacon_shop_sold_price_attribute.NumOfReceiptNotReceived;
}
PacketHandler.BeaconShopGetItemInfosPacketHandler.send_S2C_ACK_BEACON_SHOP_GET_ITEM_INFOS(player, result, beacon_shop_item_reload_data, beacon_shop_profile_attribute.DailyRegisterCount, numOfReceiptNotReceived);
return result;
}
private async Task<Result> ProcessUpdateDailyRegisterCount(UgcNpc found_ugc_npc)
{
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 (checkDailyRegisterCount(found_ugc_npc) == true)
{
var fn_update_daily_count = async delegate ()
{
var result = new Result();
var invokers = new List<ILogInvoker>();
var beacon_shop_profile_attribute = found_ugc_npc.getEntityAttribute<BeaconShopProfileAttribute>();
NullReferenceCheckHelper.throwIfNull(beacon_shop_profile_attribute, () => $"beacon_shop_profile_attribute is null !!! - {player.toBasicString()}");
updateDailyRegisterCount(beacon_shop_profile_attribute);
var batch = new QueryBatchEx<QueryRunnerWithDocument>( player, LogActionType.BeaconShopUpdateDailyCount
, 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, "BeaconShopUpdateDailyCount", fn_update_daily_count);
if (result.isFail())
{
err_msg = $"Failed to runTransactionRunnerSafely()!!! : {result.toBasicString()} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
}
}
return result;
}
private (Result, META_ID, double) checkRegisterItemToBeaconShop(string itemGuid, int itemAmount, double SellingPrice, UgcNpc ugcNpc)
{
var result = new Result();
var err_msg = string.Empty;
var player = getOwner() as Player;
NullReferenceCheckHelper.throwIfNull(player, () => $"player is null !!!");
var beacon_attribute = ugcNpc.getEntityAttribute<UgcNpcAttribute>();
NullReferenceCheckHelper.throwIfNull(beacon_attribute, () => $"beacon_attribute is null !!!");
// 1. 비컨 체크
var rental_agent_action = player.getEntityAction<RentalAgentAction>();
if (beacon_attribute.State != EntityStateType.UsingByMyHome ||
rental_agent_action.isRentalMyhome(beacon_attribute.LocatedInstanceGuid) == false)
{
err_msg = $"Beacon is not in myHome !!! : beacon State:{beacon_attribute.State} - {player.toBasicString()}";
result.setFail(ServerErrorCode.BeaconShopBeaconIsNotInRentalHome, err_msg);
return (result, 0, 0);
}
// 2. 아이템 체크
var inventory_action = player.getEntityAction<InventoryActionBase>();
var target_item = inventory_action.tryGetItemByItemGuid(itemGuid);
if (target_item == null)
{
err_msg = $"Not found item !!! : target item guid :{itemGuid} - {player.toBasicString()}";
result.setFail(ServerErrorCode.BeaconShopNotFoundItem, err_msg);
return (result, 0, 0);
}
if(target_item.getItemStackCount() < itemAmount)
{
err_msg = $"Not enough item !!! : target item meta id :{target_item.getItemMetaId()}, target item stack count : {target_item.getItemStackCount()}, request count : {itemAmount} - {player.toBasicString()}";
result.setFail(ServerErrorCode.BeaconShopNotEnoughItem, err_msg);
return (result, 0, 0);
}
var target_item_meta_data = target_item.getItemMeta();
if(target_item_meta_data == null)
{
err_msg = $"Not found item meta !!! : target item meta id :{target_item.getItemMetaId()}, target item stack count : {target_item.getItemStackCount()}, request count : {itemAmount} - {player.toBasicString()}";
result.setFail(ServerErrorCode.BeaconShopNotFoundMetaData, err_msg);
return (result, 0, 0);
}
if (target_item_meta_data.is_BeaconShop == false)
{
err_msg = $"Invalid item for Selling !!! : item meta id : {target_item.getItemMetaId()} - {player.toBasicString()}";
result.setFail(ServerErrorCode.BeaconShopInvalidItemForSell, err_msg);
return (result, 0, 0);
}
// 3. 재화 체크
if (ServerCommon.MetaHelper.GameConfigMeta.BeaconShopMinCaliumPrice > SellingPrice)
{
err_msg = $"Lower then Min price : request SellingPrice : {SellingPrice} - {player.toBasicString()}";
result.setFail(ServerErrorCode.BeaconShopLowSellingPrice, err_msg);
return (result, 0, 0);
}
if(ServerCommon.MetaHelper.GameConfigMeta.BeaconShopMaxCaliumPrice < SellingPrice)
{
err_msg = $"over then Min price : request SellingPrice : {SellingPrice} - {player.toBasicString()}";
result.setFail(ServerErrorCode.BeaconShopOverSellingPrice, err_msg);
return (result, 0, 0);
}
var req_unit_money = (double)target_item_meta_data.BeaconShopGoldFee;
var req_money = req_unit_money.calculateRoundedMoneyByCurrency(CurrencyType.Gold, itemAmount);
var money_action = player.getEntityAction<MoneyAction>();
if (money_action.hasMoney(CurrencyType.Gold, req_money) == false)
{
err_msg = $"!!! : target item meta id :{target_item.getItemMetaId()}, target item stack count : {target_item.getItemStackCount()}, request count : {itemAmount} - {player.toBasicString()}";
result.setFail(ServerErrorCode.BeaconShopNotEnoughRegisterFee, err_msg);
return (result, 0, 0);
}
// 4. 일일 등록 횟수 제한
var beacon_shop_profile_attribute = ugcNpc.getEntityAttribute<BeaconShopProfileAttribute>();
NullReferenceCheckHelper.throwIfNull(beacon_shop_profile_attribute, () => $"beacon_shop_profile_attribute is null !!!");
if( checkDailyRegisterCount(ugcNpc) == false
&& ServerCommon.MetaHelper.GameConfigMeta.BeaconShopDailyRegistration <= beacon_shop_profile_attribute.DailyRegisterCount)
{
err_msg = $"Beacon Shop daily registration count is over !!! DailyRegisterCount : {beacon_shop_profile_attribute.DailyRegisterCount} ";
result.setFail(ServerErrorCode.BeaconShopOverOneDayRegisterLimit, err_msg);
return (result, 0, 0);
}
return (result, (META_ID)target_item_meta_data.ItemId, req_money);
}
private async Task<Result> reloadBeaconShopSolds()
{
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 dynamo_db_client = server_logic.getDynamoDbClient();
var doc = new BeaconShopSoldRecordDoc(player.getUserGuid());
var query_config = dynamo_db_client.makeQueryConfigForReadByPKOnly(doc.getPK());
(result, var read_docs) = await dynamo_db_client.simpleQueryDocTypesWithQueryOperationConfig<BeaconShopSoldRecordDoc>(query_config);
if (result.isFail())
{
return result;
}
result = await AddBeaconShopSoldRecordsFromDocs(read_docs);
if(result.isFail())
{
return result;
}
var price_doc = new BeaconShopSoldPriceDoc(player.getUserGuid());
var price_query_config = dynamo_db_client.makeQueryConfigForReadByPKOnly(price_doc.getPK());
(result, var price_read_docs) = await dynamo_db_client.simpleQueryDocTypesWithQueryOperationConfig<BeaconShopSoldPriceDoc>(price_query_config);
if (result.isFail())
{
return result;
}
result = await AddBeaconShopSoldPriceFromDocs(price_read_docs);
if (result.isFail())
{
return result;
}
await ProcessBeaconShopDeleteRecord();
return result;
}
private async Task<(Result, List<BeaconShopItem>?)> ReloadBeaconShop(BEACON_GUID beaconGuid, USER_GUID beaconOwnerGuid)
{
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 !!! - {player.toBasicString()}");
(result, var found_ugc_npc, var ugc_npc_owner) = await NpcHelper.findUgcNpc(beaconGuid, beaconOwnerGuid);
if (found_ugc_npc == null)
{
if (result.isSuccess())
result.setFail(ServerErrorCode.UgcNpcNotFound, err_msg);
err_msg = $"Not found Beacon !!! : beaconGuid:{beaconGuid} beaconOwner:{beaconOwnerGuid} - {player.toBasicString()}";
return (result, null);
}
var ugc_npc_beacon_shop_action = found_ugc_npc.getEntityAction<UgcNpcBeaconShopAction>();
NullReferenceCheckHelper.throwIfNull(ugc_npc_beacon_shop_action, () => $"ugc_npc_beacon_shop_action is null !!! - {toBasicString()}");
result = await ugc_npc_beacon_shop_action.ReloadBeaconShopInventoryFromDb();
if (result.isFail())
{
err_msg = $"Failed to Reload BeaconShop from Db !!! : beaconGuid:{beaconGuid} beaconOwner:{beaconOwnerGuid} - {player.toBasicString()}";
Log.getLogger().error(err_msg);
return (result, null);
}
return (result, ugc_npc_beacon_shop_action.getHasBeaconShopItem());
}
private async Task<Result> updateBeaconShopSold()
{
var result = new Result();
if (m_isUpdateSold == true)
{
result = await reloadBeaconShopSolds();
if (result.isFail())
{
return result;
}
m_isUpdateSold = false;
}
return result;
}
}