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> m_beacon_shop_sold_records = new(); private ConcurrentDictionary 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 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(); 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 AddBeaconShopSoldRecordsFromDocs(List 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(); 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(); 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 AddBeaconShopSoldPriceFromDocs(List 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(); 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 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(); 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(); 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(); NullReferenceCheckHelper.throwIfNull(beacon_attribute, () => $"beacon_attribute is null !!!"); var ugc_npc_beacon_shop_action = ugc_npc.getEntityAction(); //1. 일일 등록 횟수 등록 var beacon_shop_profile_attribute = ugc_npc.getEntityAttribute(); 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(); (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(); 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(); NullReferenceCheckHelper.throwIfNull(beacon_shop_attribute, () => $"beacon_shop_attribute is null !!!"); //4. 등록 수수료 차감 var money_action = player.getEntityAction(); 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(sold_price_doc , (sold_price_doc) => { var sold_price_attrib = sold_price_doc.getAttrib(); 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( 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 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 BeaconShopReturnItemUpdate(ITEM_GUID itemGuid, BEACON_GUID beaconGuid) { var result = new Result(); var err_msg = string.Empty; var invokers = new List(); 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(); 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(); NullReferenceCheckHelper.throwIfNull(beacon_attribute, () => $"beacon_attribute is null !!!"); var ugc_npc_beacon_shop_action = ugc_npc.getEntityAction(); //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(); 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(); (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( 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 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 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(); 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(); 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(); 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(); 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(); 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(); 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(); 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(); (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( 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(); 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(); 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(); 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(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 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(); 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 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(); bool delete_record = false; var delete_beacon_shop_sold_records = new ConcurrentDictionary>(); 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(); 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(); 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( 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 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(); NullReferenceCheckHelper.throwIfNull(calium_storage_entity, () => $"calium_storage_entity is null !!! - {player.toBasicString()}"); var invokers = new List(); 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(); NullReferenceCheckHelper.throwIfNull(beacon_shop_sold_price_attribute, () => $"beacon_shop_sold_price_attribute is null !!! - {player.toBasicString()}"); // 1. 돈 지급 var money_action = player.getEntityAction(); 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( 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(); 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(); 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 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 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(); 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(); 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 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(); var beacon_shop_profile_attribute = found_ugc_npc.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(beacon_shop_profile_attribute, () => $"beacon_shop_profile_attribute is null !!! - {player.toBasicString()}"); updateDailyRegisterCount(beacon_shop_profile_attribute); var batch = new QueryBatchEx( 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(); NullReferenceCheckHelper.throwIfNull(beacon_attribute, () => $"beacon_attribute is null !!!"); // 1. 비컨 체크 var rental_agent_action = player.getEntityAction(); 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(); 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(); 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(); 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 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(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(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?)> 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(); 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 updateBeaconShopSold() { var result = new Result(); if (m_isUpdateSold == true) { result = await reloadBeaconShopSolds(); if (result.isFail()) { return result; } m_isUpdateSold = false; } return result; } }