using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using ServerCommon; using SESSION_ID = System.Int32; using WORLD_META_ID = System.UInt32; using META_ID = System.UInt32; using ENTITY_GUID = System.String; using ACCOUNT_ID = System.String; using OWNER_GUID = System.String; using USER_GUID = System.String; using CHARACTER_GUID = System.String; using ITEM_GUID = System.String; using ServerCore; using ServerBase; using MetaAssets; using Amazon.S3.Model; using static ServerCommon.MetaHelper; namespace GameServer { public class ItemAction : EntityActionBase { public ItemAction(ItemBase owner) : base(owner) { } public override async Task onInit() { var owner = getOwner(); NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!"); var parent = owner.getRootParent(); NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!! - {owner.toBasicString()}"); var result = new Result(); var alert_action = owner.getEntityAction(); NullReferenceCheckHelper.throwIfNull(alert_action, () => $"alert_action is null !!! - {owner.toBasicString()}, {parent.toBasicString()}"); alert_action.attachAlertFunction(EntityAlertTriggerType.ItemExpireWarningBefore, onAlertItemExpireWaringBefore); alert_action.attachAlertFunction(EntityAlertTriggerType.ItemExpire, onAlertItemExpire); return await Task.FromResult(result); } public override void onClear() { return; } public async Task<(Result, List, EntityAlertMethodType)> onAlertItemExpireWaringBefore(EntityAlertTriggerType triggerType) { var owner = getOwner() as Item; NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!"); var parent = owner.getRootParent(); NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!! - {owner.toBasicString()}"); var err_msg = string.Empty; var result = new Result(); var doc_bases = new List(); Player? player = null; if (parent is Player root_player) { player = root_player; } else if (parent is UgcNpc ugc_npc) { player = ugc_npc.onGetMasterEntity() as Player; } if (null == player) { err_msg = $"Failed to cast Player !!!, in ItemAction.onTick() - {owner.toBasicString()}, {parent.toBasicString()}"; result.setFail(ServerErrorCode.ClassTypeCastIsNull, err_msg); Log.getLogger().error(result.toBasicString()); return (result, doc_bases, EntityAlertMethodType.None); } var system_mail_key = "Item_Expiring_Soon"; if (MetaData.Instance.SystemMailMetaData.TryGetValue(system_mail_key, out var systemMailMetaData) == false) { err_msg = $"Not found SystemMailMeta !!! : mailKey:{system_mail_key} - {owner.toBasicString()}, {parent.toBasicString()}"; result.setFail(ServerErrorCode.SystemMailMetaDataNotFound, err_msg); Log.getLogger().error(err_msg); return (result, doc_bases, EntityAlertMethodType.None); } var item_meta = owner.getItemMeta(); NullReferenceCheckHelper.throwIfNull(item_meta, () => $"item_meta is null !!! - {parent.toBasicString()}"); var meta_id = (META_ID)item_meta.ItemId; var user_nickname = player.getUserNickname(); var contents_arguments = new List(); contents_arguments.Add(item_meta.getStringKeyOfItemName()); (result, var new_mail_doc) = await Mail.createSystemMailWithMeta( player.getUserGuid(), user_nickname, systemMailMetaData, contents_arguments , new List(), GameConfigMeta.SystemMailStoragePeriod ); if (result.isFail()) { err_msg = $"Failed to createSystemMailWithMeta() !!! : {result.toBasicString()} - {owner.toBasicString()}, {parent.toBasicString()}"; Log.getLogger().error(err_msg); return (result, doc_bases, EntityAlertMethodType.None); } NullReferenceCheckHelper.throwIfNull(new_mail_doc, () => $"new_mail_doc is null !!! - {player.toBasicString()}"); doc_bases.Add(new_mail_doc); var item_attribute_base = owner.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(item_attribute_base, () => $"item_attribute_base is null !!! - {player.toBasicString()}"); var alert_record_attribute = owner.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(alert_record_attribute, () => $"alert_record_attribute is null !!! - {player.toBasicString()}"); alert_record_attribute.AlertKey = EntityAlertRecordDoc.makeALERT_KEY(triggerType, meta_id); alert_record_attribute.AlertedTime = DateTimeHelper.Current; alert_record_attribute.OwnerEntityType = owner.onGetOwnerEntityType(); alert_record_attribute.OwnerGuid = item_attribute_base.ItemGuid; alert_record_attribute.EntityAlertTriggerType = triggerType; alert_record_attribute.MetaId = meta_id; alert_record_attribute.modifiedEntityAttribute(true); return (result, doc_bases, EntityAlertMethodType.Mail); } public async Task<(Result, List, EntityAlertMethodType)> onAlertItemExpire(EntityAlertTriggerType triggerType) { var owner = getOwner() as Item; NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!!"); var parent = owner.getRootParent(); NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!! - {owner.toBasicString()}"); var err_msg = string.Empty; var result = new Result(); var doc_bases = new List(); Player? player = null; if (parent is Player root_player) { player = root_player; } else if (parent is UgcNpc ugc_npc) { player = ugc_npc.onGetMasterEntity() as Player; } if (null == player) { err_msg = $"Failed to cast Player !!!, in ItemAction.onTick() - {owner.toBasicString()}, {parent.toBasicString()}"; result.setFail(ServerErrorCode.ClassTypeCastIsNull, err_msg); Log.getLogger().error(result.toBasicString()); return (result, doc_bases, EntityAlertMethodType.None); } var system_mail_key = "Item_Expired_Deleted"; if (MetaData.Instance.SystemMailMetaData.TryGetValue(system_mail_key, out var systemMailMetaData) == false) { err_msg = $"Not found SystemMailMeta !!! : mailKey:{system_mail_key} - {owner.toBasicString()}, {parent.toBasicString()}"; result.setFail(ServerErrorCode.SystemMailMetaDataNotFound, err_msg); Log.getLogger().error(err_msg); return (result, doc_bases, EntityAlertMethodType.None); } var item_meta = owner.getItemMeta(); NullReferenceCheckHelper.throwIfNull(item_meta, () => $"item_meta is null !!! - {parent.toBasicString()}"); var meta_id = (META_ID)item_meta.ItemId; var user_nickname = player.getUserNickname(); var contents_arguments = new List(); contents_arguments.Add(item_meta.getStringKeyOfItemName()); (result, var new_mail_doc) = await Mail.createSystemMailWithMeta(player.getUserGuid(), user_nickname, systemMailMetaData, contents_arguments , new List(), GameConfigMeta.SystemMailStoragePeriod); if (result.isFail()) { err_msg = $"Failed to createSystemMailWithMeta() !!! : {result.toBasicString()} - {owner.toBasicString()}, {parent.toBasicString()}"; Log.getLogger().error(err_msg); return (result, doc_bases, EntityAlertMethodType.None); } NullReferenceCheckHelper.throwIfNull(new_mail_doc, () => $"new_mail_doc is null !!! - {player.toBasicString()}"); doc_bases.Add(new_mail_doc); var item_attribute_base = owner.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(item_attribute_base, () => $"item_attribute_base is null !!! - {player.toBasicString()}"); var alert_record_attribute = owner.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(alert_record_attribute, () => $"alert_record_attribute is null !!! - {player.toBasicString()}"); alert_record_attribute.AlertKey = EntityAlertRecordDoc.makeALERT_KEY(triggerType, meta_id); alert_record_attribute.AlertedTime = DateTimeHelper.Current; alert_record_attribute.OwnerEntityType = owner.onGetOwnerEntityType(); alert_record_attribute.OwnerGuid = item_attribute_base.ItemGuid; alert_record_attribute.EntityAlertTriggerType = triggerType; alert_record_attribute.MetaId = meta_id; alert_record_attribute.modifiedEntityAttribute(true); return (result, doc_bases, EntityAlertMethodType.Mail); } public async Task<(Result, bool, List?)> tryLevelUpByTattoo() { var result = new Result(); var err_msg = string.Empty; var owner = getOwner() as Item; ArgumentNullException.ThrowIfNull(owner); var parent = owner.getRootParent(); ArgumentNullException.ThrowIfNull(parent); var inventory_action = parent.getEntityAction(); ArgumentNullException.ThrowIfNull(inventory_action); inventory_action.getEquipInvens().TryGetValue(InvenEquipType.Tattoo, out var found_equip_inven); var tattoo_inven = found_equip_inven as TattooEquipInven; ArgumentNullException.ThrowIfNull(tattoo_inven); var tattoo_inven_data = tattoo_inven.getData(); ArgumentNullException.ThrowIfNull(tattoo_inven_data); var item_attribute = owner.getEntityAttribute(); ArgumentNullException.ThrowIfNull(item_attribute); bool is_equiped_tatoo_slot = false; var tattoo_slot_type = (TattooSlotType)item_attribute.EquipedPos; var found_using_tattoo_slot = tattoo_inven_data.findEntityBaseInSlotType(tattoo_slot_type) as Item; if (null != found_using_tattoo_slot) { is_equiped_tatoo_slot = true; } var item_meta = owner.getItemMeta(); ArgumentNullException.ThrowIfNull(item_meta); var curr_level = item_attribute.Level; var next_level = item_attribute.Level + 1; // 다음 레벨에 해당하는 메타 데이터를 참조 한다. if (false == MetaData.Instance._ItemLevelEnchantMetaTable.TryGetValue(next_level, out var found_new_item_level_enchant_meta)) { err_msg = $"Not found new ItemLevelEchantMeta !!!, current level is Max : newLevel:{next_level}, currLevel:{curr_level} - {owner.toBasicString()}, {parent.toBasicString()}"; result.setFail(ServerErrorCode.ItemLevelCurrentMax, err_msg); return (result, false, null); } var found_new_enchant = found_new_item_level_enchant_meta?.GetConsumeItem(item_meta.Rarity); if (found_new_enchant == null) { err_msg = $"Not found next Enchant Data !!! : itemRarity:{item_meta.Rarity} - {owner.toBasicString()}, {parent.toBasicString()}"; result.setFail(ServerErrorCode.ItemEnchantNotFoundInMeta, err_msg); return (result, false, null); } (result, var deleted_items) = await inventory_action.tryDeleteItemByMetaId((META_ID)found_new_enchant.ConsumeItemID, (UInt16)found_new_enchant.ConsumeItemCount); if(result.isFail()) { return (result, false, null); } var is_success_enchant = false; if (found_new_enchant.Probability >= RandomHelper.next(0, 10000) == true) { if(true == is_equiped_tatoo_slot) { var ability_action = parent.getEntityAction(); ArgumentNullException.ThrowIfNull(ability_action); result = await ability_action.setAbilities(owner, (Int16)next_level, false); if (result.isFail()) { return (result, false, null); } await ability_action.setAbilities(owner, (Int16)(item_attribute.Level), true); } is_success_enchant = true; item_attribute.Level = (UInt16)next_level; item_attribute.modifiedEntityAttribute(); } var updated_items = new List(); updated_items.AddRange(deleted_items); updated_items.Add(owner); return (result, is_success_enchant, updated_items); } public async Task<(Result, List?)> tryChangeAttributeByTattoo(Int16 targetSlotIndex) { var result = new Result(); var err_msg = string.Empty; var owner = getOwner() as Item; ArgumentNullException.ThrowIfNull(owner); var parent = owner.getRootParent(); ArgumentNullException.ThrowIfNull(parent); var inventory_action = parent.getEntityAction(); ArgumentNullException.ThrowIfNull(inventory_action); inventory_action.getEquipInvens().TryGetValue(InvenEquipType.Tattoo, out var found_equip_inven); var tattoo_inven = found_equip_inven as TattooEquipInven; ArgumentNullException.ThrowIfNull(tattoo_inven); var tattoo_inven_data = tattoo_inven.getData(); ArgumentNullException.ThrowIfNull(tattoo_inven_data); var item_attribute = owner.getEntityAttribute(); ArgumentNullException.ThrowIfNull(item_attribute); bool is_equiped_tatoo_slot = false; var tattoo_slot_type = (TattooSlotType)item_attribute.EquipedPos; var found_using_tattoo_slot = tattoo_inven_data.findEntityBaseInSlotType(tattoo_slot_type) as Item; if (null != found_using_tattoo_slot) { is_equiped_tatoo_slot = true; } var item_meta = owner.getItemMeta(); ArgumentNullException.ThrowIfNull(item_meta, $"item_meta is null !!! - {parent.toBasicString()}"); if (false == MetaData.Instance.Meta.AttributeEnchantMetaTable.AttributeEnchantMetaDataListbyRarity.TryGetValue(item_meta.Rarity, out var found_attribute_enchant_meta)) { err_msg = $"Not found AttributeEnchantMeta !!! : itemRarity:{item_meta.Rarity} - {owner.toBasicString()}, {parent.toBasicString()}"; result.setFail(ServerErrorCode.ItemAttributeEnchantMetaNotFound, err_msg); return (result, null); } if (false == MetaData.Instance._ItemLevelEnchantMetaTable.TryGetValue(item_attribute.Level, out var found_item_level_enchant_meta)) { err_msg = $"Not found new ItemLevelEchantMeta !!! : newLevel:{item_attribute.Level} - {owner.toBasicString()}, {parent.toBasicString()}"; result.setFail(ServerErrorCode.ItemLevelEnchantNotFoundInMeta, err_msg); return (result, null); } var found_enchant = found_item_level_enchant_meta.GetConsumeItem(item_meta.Rarity); if (found_enchant == null) { err_msg = $"Not found new Enchant Data !!! : itemRarity:{item_meta.Rarity} - {owner.toBasicString()}, {parent.toBasicString()}"; result.setFail(ServerErrorCode.ItemEnchantNotFoundInMeta, err_msg); return (result, null); } (result, var deleted_items) = await inventory_action.tryDeleteItemByMetaId((META_ID)found_attribute_enchant_meta.ItemID, (UInt16)found_attribute_enchant_meta.ItemCount); if(result.isFail()) { return (result, null); } if(0 == targetSlotIndex) { result = owner.fillupMakeAttributeIds(item_meta, out var selected_attribute_ids); if(result.isFail()) { return (result, null); } if(true == is_equiped_tatoo_slot) { var ability_action = parent.getEntityAction(); ArgumentNullException.ThrowIfNull(ability_action); result = await ability_action.setAbilities(owner, (Int16)item_attribute.Level, true); if(result.isFail()) { return (result, null); } item_attribute.Attributes = selected_attribute_ids; result = await ability_action.setAbilities(owner, (Int16)item_attribute.Level, false); if (result.isFail()) { return (result, null); } } else { item_attribute.Attributes = selected_attribute_ids; } } else { (result, var change_attribute_id) = await owner.fillupChangeAttributeIds(); if (result.isFail()) { return (result, null); } if (true == is_equiped_tatoo_slot) { var ability_action = parent.getEntityAction(); ArgumentNullException.ThrowIfNull(ability_action); var attriubte_id = item_attribute.Attributes[targetSlotIndex]; result = await ability_action.changeAbilities( owner , new Dictionary() { { targetSlotIndex, attriubte_id } } , true ); if(result.isFail()) { return (result, null); } item_attribute.Attributes[targetSlotIndex] = (UInt16)change_attribute_id; result = await ability_action.changeAbilities( owner , new Dictionary() { { targetSlotIndex, change_attribute_id } } , false ); if(result.isFail()) { return (result, null); } } else { item_attribute.Attributes[targetSlotIndex] = (UInt16)change_attribute_id; } } item_attribute.modifiedEntityAttribute(); var updated_items = new List(); updated_items.AddRange(deleted_items); updated_items.Add(owner); return (result, updated_items); } public async Task isExpiredItem() { var owner = getOwner() as Item; ArgumentNullException.ThrowIfNull(owner); var parent = owner.getRootParent(); ArgumentNullException.ThrowIfNull(parent); var item_meta = owner.getItemMeta(); NullReferenceCheckHelper.throwIfNull(item_meta, () => $"item_meta is null !!! - {parent.toBasicString()}"); if( EExpireType.DELAY != item_meta.ExpireType || 0 >= item_meta.ExpireTimeSec ) { return false; } var item_attribute_base = owner.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(item_attribute_base, () => $"item_attribute_base is null !!! - {parent.toBasicString()}"); (var result, DynamoDbDocBase? doc_base) = await item_attribute_base.toDocBase(false); if(result.isFail()) { var err_msg = $"Failed to toDocBase() !!!, in isExpiredItem() : {result.toBasicString()} - {owner.toBasicString()}, {parent.toBasicString()}"; Log.getLogger().error(err_msg); return false; } NullReferenceCheckHelper.throwIfNull(doc_base, () => $"doc_base is null !!! - {owner.toBasicString()}, {parent.toBasicString()}"); var created_time = doc_base.getCreatedDateTime().ProcessedTime; if (false == created_time.isValidTime()) { var err_msg = $"Failed to isValidTime() !!!, in isExpiredItem() : {result.toBasicString()} - {owner.toBasicString()}, {parent.toBasicString()}"; Log.getLogger().error(err_msg); return false; } var to_expire_date_time = created_time.AddSeconds(item_meta.ExpireTimeSec); if(false == DateTimeHelper.hasTimeReached(to_expire_date_time)) { await onAlertItemExpireBeforeHourTime(created_time, to_expire_date_time); return false; } return true; } public async Task onAlertItemExpireBeforeHourTime(DateTime createdTime, DateTime toExpireTime) { var owner = getOwner() as Item; NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!! - {toBasicString()}"); var parent = owner.getRootParent(); NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!! - {owner.toBasicString()}"); var past_time = MetaHelper.GameConfigMeta.ItemExpireAlertBeforeHourTime * -1; var alert_time = toExpireTime.AddHours(past_time); if (false == DateTimeHelper.hasTimeReached(alert_time)) { return; } var entity_alert_auction = owner.getEntityAction(); NullReferenceCheckHelper.throwIfNull(entity_alert_auction, () => $"entity_alert_auction is null !!! - {owner.toBasicString()}, {parent.toBasicString()}"); await entity_alert_auction.onAlert(EntityAlertTriggerType.ItemExpireWarningBefore); } public override async Task onTick() { await Task.CompletedTask; var owner = getOwner() as Item; NullReferenceCheckHelper.throwIfNull(owner, () => $"owner is null !!! - {toBasicString()}"); var parent = owner.getRootParent(); NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!! - {owner.toBasicString()}"); var err_msg = string.Empty; var result = new Result(); var item_attribute_base = owner.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(item_attribute_base, () => $"item_attribute_base is null !!! - {owner.toBasicString()}"); Player? player = null; if (parent is Player root_player) { player = root_player; } else if (parent is UgcNpc ugc_npc) { player = ugc_npc.onGetMasterEntity() as Player; } if (null == player) { err_msg = $"Failed to cast Player !!!, in ItemAction.onTick() - {owner.toBasicString()}, {parent.toBasicString()}"; result.setFail(ServerErrorCode.ClassTypeCastIsNull, err_msg); Log.getLogger().error(result.toBasicString()); return; } var target_item_guid = item_attribute_base.ItemGuid; var item_stack_count = item_attribute_base.ItemStackCount; if (true == await isExpiredItem()) { var entity_alert_auction = owner.getEntityAction(); NullReferenceCheckHelper.throwIfNull(entity_alert_auction, () => $"entity_alert_auction is null !!! - {owner.toBasicString()}, {parent.toBasicString()}"); await entity_alert_auction.onAlert(EntityAlertTriggerType.ItemExpire); (result, _) = await PacketHandler.ItemDeletePacketHandler.tryDeleteItemWithTransactionRunner( player , target_item_guid , item_stack_count , LogActionType.ItemDestoryByExpiration ); if (result.isFail()) { err_msg = $"Failed to tryDeleteItemWithTransactionRunner() !!!, in onTick() : {result.toBasicString()} - {owner.toBasicString()}, {parent.toBasicString()}"; Log.getLogger().error(err_msg); return; } var user_create_or_load_action = player.getEntityAction(); NullReferenceCheckHelper.throwIfNull(user_create_or_load_action, () => $"user_create_or_load_action is null !!! - {player.toBasicString()}"); ItemNotifyHelper.send_S2C_NTF_ITEM_DELETE(player, target_item_guid, item_stack_count); } } } }