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

1174 lines
50 KiB
C#

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Amazon.Runtime.Internal.Transform;
using ServerCore; using ServerBase;
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 Amazon.S3.Model;
using MetaAssets;
using Nettention.Proud;
namespace GameServer
{
public class BagTab
{
private readonly BagTabType m_bag_tab_type;
private InventoryBase<ENTITY_GUID> m_owner;
private readonly string m_usable_inven_bag_name;
public UInt16 TakeInItemCount { get; private set; } = 0;
public BagTab(InventoryBase<ENTITY_GUID> owner, BagTabType bagTabType)
{
m_owner = owner;
m_bag_tab_type = bagTabType;
m_usable_inven_bag_name = bagTabType.toUsableInvenBagName();
}
public bool tryCheckTakableInItem(Int16 toIncCount, Int16 reservedCount = 0)
{
if( getSlotMaxCount() < (TakeInItemCount + reservedCount + toIncCount) )
{
return false;
}
return true;
}
public bool tryTakableInItem()
{
if (getSlotMaxCount() <= TakeInItemCount)
{
return false;
}
TakeInItemCount += 1;
return true;
}
public bool tryCheckTakableOutItem(Int16 toDecCount, Int16 reservedCount = 0)
{
if ( 0 > (TakeInItemCount + reservedCount - toDecCount) )
{
return false;
}
return true;
}
public bool tryTakableOutItem()
{
if (0 >= TakeInItemCount)
{
return false;
}
TakeInItemCount -= 1;
return true;
}
public bool onMergeTakeInItemCount(Int16 reservedCount)
{
var inventory_base = getInventoryBase();
NullReferenceCheckHelper.throwIfNull(inventory_base, () => $"inventory_base is null !!!");
var root_parent = inventory_base.getRootParent();
NullReferenceCheckHelper.throwIfNull(root_parent, () => $"root_parent is null !!! - {inventory_base.toBasicString()}");
var to_update_count = TakeInItemCount + reservedCount;
if (to_update_count < 0 || InventoryRuleHelper.getBagTapMaxSlotCountByBagTabType(root_parent.getEntityType(), getBagTabType()) < to_update_count)
{
return false;
}
TakeInItemCount = (UInt16)to_update_count;
return true;
}
public BagTabType getBagTabType() => m_bag_tab_type;
public Int32 getSlotMaxCount()
{
var inventory_base = getInventoryBase();
NullReferenceCheckHelper.throwIfNull(inventory_base, () => $"inventory_base is null !!!");
var root_parent = inventory_base.getRootParent();
NullReferenceCheckHelper.throwIfNull(root_parent, () => $"root_parent is null !!! - {inventory_base.toBasicString()}");
return InventoryRuleHelper.getBagTapMaxSlotCountByBagTabType(root_parent.getEntityType(), getBagTabType());
}
public void resetItemCount()
{
TakeInItemCount = 0;
}
public InventoryBase<ENTITY_GUID> getInventoryBase() => m_owner;
public string toBasicString()
{
return $"{this.getTypeName()}, UsableInvenBagName:{m_usable_inven_bag_name}";
}
}
public class BagInven : InventoryBase<ITEM_GUID>
{
// BagTabType에 장착되어 아이템 있는 개수
private ConcurrentDictionary<BagTabType, BagTab> m_bag_tab_take_in_counts = new();
public BagInven(EntityBase owner)
: base(EntityType.BagInven, owner)
{
base.onInitSlots(ServerCommon.Constant.BagSlotDefaultMaxCount);
}
public override async Task<Result> onInit()
{
await Task.CompletedTask;
var parent = getDirectParent();
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!!");
var result = new Result();
var bag_tab_types = EnumHelper.getValuesWithoutScopeAll<BagTabType>();
foreach (var bag_tab in bag_tab_types)
{
m_bag_tab_take_in_counts.TryAdd(bag_tab, new BagTab(this, bag_tab));
}
return result;
}
public void resetItemCountInTabs()
{
foreach(var each in m_bag_tab_take_in_counts)
{
var bag_tab = each.Value;
bag_tab.resetItemCount();
}
}
public async Task<(Result, List<Item>)> tryTakableInItemBase(META_ID toTakeInItemMetaId, UInt16 toTakeInCount)
{
await Task.CompletedTask;
var parent = getDirectParent();
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!!");
var bag_item_data = getData();
NullReferenceCheckHelper.throwIfNull(bag_item_data, () => $"bag_item_data is null !!! - {parent.toBasicString()}");
var result = new Result();
var reserved_items = new List<Item>();
var err_msg = string.Empty;
// 1. 아이템 메타 정보를 얻는다.
if (false == MetaData.Instance._ItemTable.TryGetValue((int)toTakeInItemMetaId, out var itemMetaData))
{
err_msg = $"Not found ItemMeta !!! : itemMetaId:{toTakeInItemMetaId} - {parent.toBasicString()}";
result.setFail(ServerErrorCode.ItemMetaDataNotFound, err_msg);
Log.getLogger().error(result.toBasicString());
return (result, reserved_items);
}
if(true == itemMetaData.IsUiOnly)
{
err_msg = $"Returned without creation Item !!!, because UI-only item : itemMetaId:{toTakeInItemMetaId} - {parent.toBasicString()}";
Log.getLogger().debug(err_msg);
return (result, reserved_items);
}
// 2. 동일한 종류의 ItemAttributeBase 목록과 보유 개수를 얻는다.
(result, var target_item_attributes, var item_has_count) = findItemAttributeBaseAllByMetaId(toTakeInItemMetaId, toTakeInCount);
if (result.isFail())
{
return (result, reserved_items);
}
// 3. 해당 아이템의 최대 Stack 개수를 초과했는지 체크 한다.
var item_total_count = item_has_count + toTakeInCount;
if (item_total_count > itemMetaData.MaxCount)
{
err_msg = $"Item max count exceed !!! : totalCount:{item_total_count} <= maxCount:{itemMetaData.MaxCount}, itemMetaId:{toTakeInItemMetaId}, {parent.toBasicString()}";
result.setFail(ServerErrorCode.ItemMaxCountExceed, err_msg);
Log.getLogger().error(result.toBasicString());
return (result, reserved_items);
}
// 4. 아이템 Stack 개수가 큰 순서로 정렬 시킨다.
var remain_count = toTakeInCount;
target_item_attributes.OrderBy(x => { return x.ItemStackCount; });
// 5. 동일한 종류의 아이템에 최대 Stack 개수이내로 추가 한다.
foreach (var item_attribute in target_item_attributes)
{
if (remain_count <= 0)
{
break;
}
var max_count = itemMetaData.StackMaxCount;
var to_modify_item = item_attribute.getOwner() as Item;
NullReferenceCheckHelper.throwIfNull(to_modify_item, () => $"to_modify_item is null !!! - {parent.toBasicString()}");
var to_modify_item_attribute = to_modify_item.getEntityAttribute<ItemAttributeBase>();
NullReferenceCheckHelper.throwIfNull(to_modify_item_attribute, () => $"to_modify_item_attribute is null !!! - {parent.toBasicString()}");
var has_count = to_modify_item_attribute.ItemStackCount;
if (has_count >= itemMetaData.StackMaxCount)
{
continue;
}
var to_add_count = 0;
// 남은 아이템 개수도 추가 가능한지 체크 한다 !!!
if (has_count + remain_count > max_count)
{
to_add_count = max_count - has_count;
}
else
{
to_add_count = remain_count;
}
to_modify_item_attribute.ItemStackCount += (ushort)to_add_count;
remain_count -= (ushort)to_add_count;
to_modify_item_attribute.modifiedEntityAttribute();
reserved_items.Add(to_modify_item);
}
// 6. 추가해야 하는 아이템 개수가 있다면
if(0 < remain_count)
{
// 6.1. 아이템 생성하고 추가 한다.
var server_logic = GameServerApp.getServerLogic();
NullReferenceCheckHelper.throwIfNull(server_logic, () => $"server_logic is null !!! - {parent.toBasicString()}");
var inventory_rule = server_logic.findRule<InventoryRule>();
NullReferenceCheckHelper.throwIfNull(inventory_rule, () => $"inventory_rule is null !!! - {parent.toBasicString()}");
var inventory_action = parent.getEntityAction<InventoryActionBase>();
NullReferenceCheckHelper.throwIfNull(inventory_action, () => $"inventory_action is null !!! - {parent.toBasicString()}");
var to_create_count = remain_count;
while (to_create_count > 0)
{
var new_item = inventory_action.onAllocItem();
if(null == new_item)
{
err_msg = $"Failed to alloc Item by ItemMeta !!! : itemMetaId:{toTakeInItemMetaId}, count:{to_create_count} - {parent.toBasicString()}";
result.setFail(ServerErrorCode.ItemAllocFailed, err_msg);
return (result, reserved_items);
}
result = await new_item.createByItemMeta(toTakeInItemMetaId, to_create_count);
if (result.isFail())
{
err_msg = $"Failed to create Item !!! : {result.toBasicString()}";
Log.getLogger().error(err_msg);
return (result, reserved_items);
}
var item_item_meta = new_item.getItemMeta();
NullReferenceCheckHelper.throwIfNull(item_item_meta, () => $"item_item_meta is null !!! - {parent.toBasicString()}");
var found_bag_rules = inventory_rule.getBagRulesByItemLargeType(item_item_meta.TypeLarge);
NullReferenceCheckHelper.throwIfNull(found_bag_rules, () => $"found_bag_rules is null !!! - {parent.toBasicString()}");
foreach (var bag_rule in found_bag_rules)
{
result = tryIncItemCountInBagTap(new_item, bag_rule);
if (result.isFail())
{
err_msg = $"Failed to tryIncItemCountInBagTap() !!! : {result.toBasicString()} - {new_item.toBasicString()}, {parent.toBasicString()}";
Log.getLogger().error(err_msg);
return (result, reserved_items);
}
break;
}
to_create_count -= new_item.getItemStackCount();
var item_attribute = new_item.getEntityAttribute<ItemAttributeBase>();
NullReferenceCheckHelper.throwIfNull(item_attribute, () => $"item_attribute is null !!! - {new_item.toBasicString()}, {parent.toBasicString()}");
result = onTryTakeInEntityBase(item_attribute.ItemGuid, new_item);
if (result.isFail())
{
return (result, reserved_items);
}
reserved_items.Add(new_item);
}
}
return (result, reserved_items);
}
public async Task<(Result, Item?)> tryTakableInItemBase(ItemDoc doc, bool isWriteToDb = false)
{
var result = new Result();
var err_msg = string.Empty;
var parent = getDirectParent();
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!!");
var server_logic = GameServerApp.getServerLogic();
NullReferenceCheckHelper.throwIfNull(server_logic, () => $"server_logic is null !!! - {parent.toBasicString()}");
var inventory_rule = server_logic.findRule<InventoryRule>();
NullReferenceCheckHelper.throwIfNull(inventory_rule, () => $"item_attribute is null !!! - {parent.toBasicString()}");
var item_doc_attrib = doc.getAttrib<ItemAttrib>();
NullReferenceCheckHelper.throwIfNull(item_doc_attrib, () => $"item_doc_attrib is null !!! - {parent.toBasicString()}");
var found_duplicated_item = findEntityBase(item_doc_attrib.ItemGuid);
if(null != found_duplicated_item)
{
err_msg = $"Found duplicated Item from ItemDoc !!! : duplicatedItem:{found_duplicated_item.toBasicString()} - {doc.toBasicString()}, {parent.toBasicString()}";
result.setFail(ServerErrorCode.ItemDocLoadDuplicatedItem, err_msg);
Log.getLogger().error(result.toBasicString());
return (result, null);
}
var inventory_action = parent.getEntityAction<InventoryActionBase>();
NullReferenceCheckHelper.throwIfNull(inventory_action, () => $"inventory_action is null !!! - {parent.toBasicString()}");
var new_item = inventory_action.onAllocItem();
if (null == new_item)
{
err_msg = $"Failed to alloc Item by ItemDoc !!! : itemGuid:{item_doc_attrib.ItemGuid}, itemMetaId:{item_doc_attrib.ItemMetaId} - {parent.toBasicString()}";
result.setFail(ServerErrorCode.ItemAllocFailed, err_msg);
return (result, null);
}
result = await new_item.createByItemDoc(doc, isWriteToDb);
if (result.isFail())
{
err_msg = $"Failed to create Item !!! : {result.toBasicString()}";
Log.getLogger().error(err_msg);
return (result, null);
}
var item_item_meta = new_item.getItemMeta();
NullReferenceCheckHelper.throwIfNull(item_item_meta, () => $"item_item_meta is null !!! - {parent.toBasicString()}");
var found_bag_rules = inventory_rule.getBagRulesByItemLargeType(item_item_meta.TypeLarge);
NullReferenceCheckHelper.throwIfNull(found_bag_rules, () => $"found_bag_rules is null !!! - {parent.toBasicString()}");
foreach (var bag_rule in found_bag_rules)
{
result = tryIncItemCountInBagTap(new_item, bag_rule);
if (result.isFail())
{
err_msg = $"Failed to tryIncItemCountInBagTap() !!! : {result.toBasicString()} - {new_item.toBasicString()}, {parent.toBasicString()}";
Log.getLogger().error(err_msg);
return (result, null);
}
break;
}
var item_attribute = new_item.getEntityAttribute<ItemAttributeBase>();
NullReferenceCheckHelper.throwIfNull(item_attribute, () => $"item_attribute is null !!! - {parent.toBasicString()}");
result = onTryTakeInEntityBase(item_attribute.ItemGuid, new_item);
if(result.isFail())
{
return (result, null);
}
return (result, new_item);
}
private Result tryIncItemCountInBagTap(Item toTakeInItem, BagRule bagRule)
{
var parent = getDirectParent();
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!!");
NullReferenceCheckHelper.throwIfNull(toTakeInItem, () => $"toTakeInItem is null !!! - {parent.toBasicString()}");
NullReferenceCheckHelper.throwIfNull(bagRule, () => $"bagRule is null !!! - {parent.toBasicString()}");
var item_meta = toTakeInItem.getItemMeta();
NullReferenceCheckHelper.throwIfNull(item_meta, () => $"item_meta is null !!! - {parent.toBasicString()}");
var result = new Result();
var err_msg = string.Empty;
var target_bag_type = bagRule.InvenBagType;
var usable_bag_tab_type = target_bag_type.toUsableBagTabType().toNFTTabOffset(item_meta);
// Transaction 활성화 상태일 경우
var transaction_runner = parent.findTransactionRunner(TransactionIdType.PrivateContents);
if (null != transaction_runner)
{
if (true == m_bag_tab_take_in_counts.TryGetValue(usable_bag_tab_type, out var found_tab))
{
// 슬롯에 예약된 아이템 개수까지 확인하여 보관 가능 여부를 체크 한다.
var reserved_count = 0;
var found_reserved_slot = transaction_runner.findReservedSlot(parent, getEntityType(), usable_bag_tab_type.convertEnumToEnumTypeAndValueString());
if (null != found_reserved_slot)
{
reserved_count += found_reserved_slot.getReservedCount();
}
var inc_slot_count = 1;
if (false == found_tab.tryCheckTakableInItem((Int16)inc_slot_count, (Int16)reserved_count))
{
err_msg = $"Failed to tryCheckTakableInItem() !!!, Bag is reserved item full : incSlotCount:{inc_slot_count}, reservedSlotCount:{reserved_count}"
+ $" - {toTakeInItem.toBasicString()}, usableInvenBagName:{usable_bag_tab_type.toUsableInvenBagName()}, {parent.toBasicString()}";
result.setFail(ServerErrorCode.BagIsReservedItemFull, err_msg);
Log.getLogger().error(result.toBasicString());
return result;
}
}
// 예약 슬롯 개수를 증가 시킨다.
result = transaction_runner.tryIncReserveSlotCount(parent, getEntityType(), usable_bag_tab_type.convertEnumToEnumTypeAndValueString());
if (result.isFail())
{
return result;
}
err_msg = $"Succss tryEquipToReserveSlot() : targetSlotType:{usable_bag_tab_type.convertEnumToEnumTypeAndValueString()} - {toBasicString()}, {parent.toBasicString()}";
Log.getLogger().info(err_msg);
return result;
}
if (false == m_bag_tab_take_in_counts.TryGetValue(usable_bag_tab_type, out var found_bag_tab))
{
found_bag_tab = new BagTab(this, usable_bag_tab_type);
m_bag_tab_take_in_counts.TryAdd(usable_bag_tab_type, found_bag_tab);
}
if(false == found_bag_tab.tryTakableInItem())
{
err_msg = $"Failed to tryTakableInItem() !!!, Bag is item full - {toTakeInItem.toBasicString()}, {found_bag_tab.toBasicString()}, {parent.toBasicString()}";
result.setFail(ServerErrorCode.BagIsReservedItemFull, err_msg);
Log.getLogger().error(result.toBasicString());
return result;
}
return result;
}
public async Task<(Result, List<Item>)> tryTakableOutItemBase(META_ID toUnequipMetaId, UInt32 toTakeOutCount = UInt32.MaxValue)
{
var parent = getDirectParent();
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!!");
var result = new Result();
var err_msg = string.Empty;
var reserved_items = new List<Item>();
// 1. 아이템 메타 정보를 얻는다.
if (false == MetaData.Instance._ItemTable.TryGetValue((int)toUnequipMetaId, out var itemMetaData))
{
err_msg = $"Not found ItemMeta !!! : itemMetaId:{toUnequipMetaId} - {parent.toBasicString()}";
result.setFail(ServerErrorCode.ItemMetaDataNotFound, err_msg);
Log.getLogger().error(result.toBasicString());
return (result, reserved_items);
}
// 2. 동일한 종류의 ItemAttributeBase 목록과 보유 개수를 얻는다.
(result, var target_item_attributes, var item_has_count) = findItemAttributeBaseAllByMetaId(toUnequipMetaId, toTakeOutCount);
if (result.isFail())
{
return (result, reserved_items);
}
// 3. 보유하고 있는 아이템 개수를 체크 한다.
if ( UInt32.MaxValue != toTakeOutCount
&& item_has_count < toTakeOutCount)
{
err_msg = $"Not enough Item Count !!! : totalCount:{item_has_count} > reqCount:{toTakeOutCount}, itemMetaId:{toUnequipMetaId}, {parent.toBasicString()}";
result.setFail(ServerErrorCode.ItemCountNotEnough, err_msg);
Log.getLogger().error(result.toBasicString());
return (result, reserved_items);
}
var to_take_out_items = new Dictionary<ItemAttributeBase, UInt16>();
var remain_count = toTakeOutCount;
if (UInt32.MaxValue == toTakeOutCount)
{
remain_count = (UInt16)target_item_attributes.Sum(x => x.ItemStackCount);
}
// 4. 아이템 개수가 많은 순서로 정렬 시킨다.
target_item_attributes.OrderBy(x => (x.ItemStackCount));
// 5. 동일한 종류의 아이템에서 Takeout할 아이템 개수만큼 차감한다.
foreach (var item_attribute in target_item_attributes)
{
if (remain_count <= 0)
{
break;
}
var to_modify_item = item_attribute.getOwner() as Item;
NullReferenceCheckHelper.throwIfNull(to_modify_item, () => $"to_modify_item is null !!! - {parent.toBasicString()}");
var to_modify_item_attribute = to_modify_item.getEntityAttribute<ItemAttributeBase>();
NullReferenceCheckHelper.throwIfNull(to_modify_item_attribute, () => $"to_modify_item_attribute is null !!! - {parent.toBasicString()}");
UInt16 to_take_out_count = 0;
// 5.1. Takeout 가능 개수를 계산 한다.
if (item_attribute.ItemStackCount > remain_count)
{
to_take_out_count = (UInt16)remain_count;
remain_count = 0;
}
else
{
to_take_out_count = item_attribute.ItemStackCount;
remain_count -= to_take_out_count;
}
to_take_out_items.Add(item_attribute, to_take_out_count);
}
foreach(var each in to_take_out_items)
{
var item_attribute = each.Key as ItemAttributeBase;
NullReferenceCheckHelper.throwIfNull(item_attribute, () => $"item_attribute is null !!! - {parent.toBasicString()}");
(result, var take_out_item) = await tryTakableOutItemBase(item_attribute.ItemGuid, each.Value);
if(result.isFail())
{
return (result, reserved_items);
}
NullReferenceCheckHelper.throwIfNull(take_out_item, () => $"take_out_item is null !!! - {parent.toBasicString()}");
reserved_items.Add(take_out_item);
}
return (result, reserved_items);
}
public async Task<(Result, Item?)> tryTakableOutItemBase(ITEM_GUID toUnequipItemGuid, UInt16 toTakeOutCount)
{
var parent = getDirectParent();
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!!");
var result = new Result();
var err_msg = string.Empty;
var server_logic = GameServerApp.getServerLogic();
NullReferenceCheckHelper.throwIfNull(server_logic, () => $"server_logic is null !!! - {parent.toBasicString()}");
var inventory_rule = server_logic.findRule<InventoryRule>();
NullReferenceCheckHelper.throwIfNull(inventory_rule, () => $"inventory_rule is null !!! - {parent.toBasicString()}");
// 1. 가방에서 아이템을 찾는다.
var found_item = findEntityBase(toUnequipItemGuid) as Item;
if(null == found_item)
{
err_msg = $"Not found Item !!!, findEntityBase() : itemGuid:{toUnequipItemGuid} - {parent.toBasicString()}";
result.setFail(ServerErrorCode.ItemNotFound, err_msg);
Log.getLogger().error(result.toBasicString());
return (result, null);
}
var found_item_meta = found_item.getItemMeta();
NullReferenceCheckHelper.throwIfNull(found_item_meta, () => $"found_item_meta is null !!! - {parent.toBasicString()}");
// 2. 아이템 개수의 차감 가능 여부를 체크하고
// 아이템 개수 차감 => 아이템 삭제 => BagTab 개수 차감을 처리 한다.
var item_attribute = found_item.getEntityAttribute<ItemAttributeBase>();
NullReferenceCheckHelper.throwIfNull(item_attribute, () => $"item_attribute is null !!! - {parent.toBasicString()}");
if (item_attribute.ItemStackCount < toTakeOutCount)
{
err_msg = $"Not enough ItemStackCount !!! : hasCount:{item_attribute.ItemStackCount} > reqCount:{toTakeOutCount}, itemGuid:{toUnequipItemGuid} - {parent.toBasicString()}";
result.setFail(ServerErrorCode.ItemStackCountNotEnough, err_msg);
Log.getLogger().error(result.toBasicString());
return (result, null);
}
else if(item_attribute.ItemStackCount > toTakeOutCount)
{
item_attribute.ItemStackCount -= toTakeOutCount;
item_attribute.modifiedEntityAttribute();
}
else
{
result = onTryTakeOutEnityBase(toUnequipItemGuid, out _);
if(result.isFail())
{
return (result, null);
}
item_attribute.ItemStackCount = 0;
item_attribute.deleteEntityAttribute();
}
if (0 == item_attribute.ItemStackCount)
{
var found_bag_rules = inventory_rule.getBagRulesByItemLargeType(found_item_meta.TypeLarge);
NullReferenceCheckHelper.throwIfNull(found_bag_rules, () => $"found_bag_rules is null !!! - {parent.toBasicString()}");
foreach (var bag_rule in found_bag_rules)
{
result = tryDecItemCountInBagTap(found_item, bag_rule);
if (result.isFail())
{
err_msg = $"Failed to tryDecItemCountInBagTap() !!! : {result.toBasicString()} - {found_item.toBasicString()}, {parent.toBasicString()}";
Log.getLogger().error(err_msg);
return (result, null);
}
break;
}
}
return await Task.FromResult((result, found_item));
}
private Result tryDecItemCountInBagTap(Item toRemoveItem, BagRule bagRule)
{
var parent = getDirectParent();
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!!");
NullReferenceCheckHelper.throwIfNull(toRemoveItem, () => $"toRemoveItem is null !!! - {parent.toBasicString()}");
NullReferenceCheckHelper.throwIfNull(bagRule, () => $"bagRule is null !!! - {parent.toBasicString()}");
var item_meta = toRemoveItem.getItemMeta();
NullReferenceCheckHelper.throwIfNull(item_meta, () => $"item_meta is null !!! - {parent.toBasicString()}");
var result = new Result();
var err_msg = string.Empty;
var target_bag_type = bagRule.InvenBagType;
var usable_bag_tab_type = target_bag_type.toUsableBagTabType().toNFTTabOffset(item_meta);
// Transaction 활성화 상태일 경우
var transaction_runner = parent.findTransactionRunner(TransactionIdType.PrivateContents);
if (null != transaction_runner)
{
if (true == m_bag_tab_take_in_counts.TryGetValue(usable_bag_tab_type, out var found_tab))
{
// 슬롯에 예약된 아이템 개수까지 확인하여 차감 가능 여부를 체크 한다.
var reserved_count = 0;
var found_reserved_slot = transaction_runner.findReservedSlot(parent, getEntityType(), usable_bag_tab_type.convertEnumToEnumTypeAndValueString());
if (null != found_reserved_slot)
{
reserved_count += found_reserved_slot.getReservedCount();
}
var dec_slot_count = 1;
if (false == found_tab.tryCheckTakableOutItem((Int16)dec_slot_count, (Int16)reserved_count))
{
err_msg = $"Failed to tryCheckTakableOutItem() !!!, Bag is reserved item empty - decSlotCount:{dec_slot_count}, reservedSlotCount:{reserved_count} - {toRemoveItem.toBasicString()}, {parent.toBasicString()}";
result.setFail(ServerErrorCode.BagIsReservedItemEmpty, err_msg);
Log.getLogger().error(result.toBasicString());
return result;
}
}
// 예약 슬롯 개수를 감소 시킨다.
result = transaction_runner.tryDecToReserveSlotCount(parent, getEntityType(), usable_bag_tab_type.convertEnumToEnumTypeAndValueString());
if (result.isFail())
{
return result;
}
err_msg = $"Success tryUnequipToReserveSlot() : targetSlotType:{usable_bag_tab_type.convertEnumToEnumTypeAndValueString()} - {toBasicString()}, {parent.toBasicString()}";
Log.getLogger().info(err_msg);
return result;
}
if (false == m_bag_tab_take_in_counts.TryGetValue(usable_bag_tab_type, out var found_bag_tab))
{
found_bag_tab = new BagTab(this, usable_bag_tab_type);
m_bag_tab_take_in_counts.TryAdd(usable_bag_tab_type, found_bag_tab);
}
if (false == found_bag_tab.tryTakableOutItem())
{
err_msg = $"Failed to tryTakableOutItem() !!!, Bag is item empty - {toRemoveItem.toBasicString()}, {found_bag_tab.toBasicString()}, {parent.toBasicString()}";
result.setFail(ServerErrorCode.BagIsItemEmpty, err_msg);
Log.getLogger().error(result.toBasicString());
return result;
}
return result;
}
public async Task<(Result, Item?, Item?)> tryDivideItem(ITEM_GUID toDivideitemGuid, UInt16 toDivideCount = 1)
{
var result = new Result();
var err_msg = string.Empty;
var parent = getDirectParent();
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!!");
(result, var divided_item) = await tryTakableOutItemBase(toDivideitemGuid, toDivideCount);
if (result.isFail())
{
return (result, null, null);
}
NullReferenceCheckHelper.throwIfNull(divided_item, () => $"take_out_item is null !!! - {parent.toBasicString()}");
var divided_item_meta = divided_item.getItemMeta();
NullReferenceCheckHelper.throwIfNull(divided_item_meta, () => $"server_logic is null !!! - {parent.toBasicString()}");
(result, var new_item) = await tryCreateItemByMeta((META_ID)divided_item_meta.ItemId, toDivideCount);
if (result.isFail())
{
return (result, null, null);
}
NullReferenceCheckHelper.throwIfNull(divided_item, () => $"take_out_item is null !!! - {parent.toBasicString()}");
return (result, divided_item, new_item);
}
async Task<(Result, Item?)> tryCreateItemByMeta(META_ID toCreateItemMetaId, UInt16 toCreateCount)
{
var result = new Result();
var err_msg = string.Empty;
var parent = getDirectParent();
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!!");
var inventory_action = parent.getEntityAction<InventoryActionBase>();
NullReferenceCheckHelper.throwIfNull(inventory_action, () => $"inventory_action is null !!! - {parent.toBasicString()}");
var new_item = inventory_action.onAllocItem();
if (null == new_item)
{
err_msg = $"Failed to alloc Item by ItemMeta !!! : itemMetaId:{toCreateItemMetaId}, count:{toCreateCount} - {parent.toBasicString()}";
result.setFail(ServerErrorCode.ItemAllocFailed, err_msg);
return (result, null);
}
result = await new_item.createByItemMeta(toCreateItemMetaId, toCreateCount);
if (result.isFail())
{
err_msg = $"Failed to create Item !!! : {result.toBasicString()}";
Log.getLogger().error(err_msg);
return (result, null);
}
return (result, new_item);
}
public Result onMergeTakeInItem(Item takeInItem)
{
var parent = getDirectParent();
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!!");
NullReferenceCheckHelper.throwIfNull(takeInItem, () => $"takeInItem is null !!! - {parent.toBasicString()}");
var result = new Result();
var err_msg = string.Empty;
var item_attribute = takeInItem.getEntityAttribute<ItemAttributeBase>();
NullReferenceCheckHelper.throwIfNull(item_attribute, () => $"item_attribute is null !!! - {parent.toBasicString()}");
var error_code = getData().onTryEquipWithEntityBase(item_attribute.ItemGuid, takeInItem);
if (error_code.isFail())
{
err_msg = $"Failed to onTryEquipWithEntityBase() !!! : {error_code.toBasicString()} - {parent.toBasicString()}";
result.setFail(error_code, err_msg);
Log.getLogger().error(result.toBasicString());
return result;
}
return result;
}
public Result onMergeTakeOutItem(Item takeOutItem)
{
var parent = getDirectParent();
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!!");
NullReferenceCheckHelper.throwIfNull(takeOutItem, () => $"takeOutItem is null !!! - {parent.toBasicString()}");
var result = new Result();
var err_msg = string.Empty;
var item_attribute = takeOutItem.getEntityAttribute<ItemAttributeBase>();
NullReferenceCheckHelper.throwIfNull(item_attribute, () => $"item_attribute is null !!! - {parent.toBasicString()}");
var error_code = getData().onTryUnequipWithEntityBase(item_attribute.ItemGuid, out var unequiped_item);
if (error_code.isFail())
{
err_msg = $"Failed to onTryUnequipWithEntityBase() !!! : {error_code.toBasicString()} - {parent.toBasicString()}";
result.setFail(error_code, err_msg);
Log.getLogger().error(result.toBasicString());
return result;
}
return result;
}
public bool hasItemByMetaId(META_ID itemMetaId, UInt32 toCheckCount = 1)
{
var parent = getDirectParent();
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!!");
var found_items = new List<Item>();
var has_items = getHasItemBases();
NullReferenceCheckHelper.throwIfNull(has_items, () => $"has_items is null !!! - {parent.toBasicString()}");
var found_item_count = 0;
foreach (var item_base in has_items)
{
var item = item_base as Item;
NullReferenceCheckHelper.throwIfNull(item, () => $"item is null !!! - {parent.toBasicString()}");
var item_meta = item.getItemMeta();
NullReferenceCheckHelper.throwIfNull(item_meta, () => $"item_meta is null !!! - {parent.toBasicString()}");
if (item_meta.ItemId != itemMetaId)
{
continue;
}
found_item_count += item.getItemStackCount();
if (toCheckCount <= found_item_count)
{
return true;
}
}
return false;
}
public ConcurrentDictionary<META_ID, UInt16> getItemsCountByMetaIds(List<META_ID> itemMetaIds)
{
var parent = getDirectParent();
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!!");
var found_items = new ConcurrentDictionary<META_ID, UInt16>();
var has_items = getHasItemBases();
NullReferenceCheckHelper.throwIfNull(has_items, () => $"has_items is null !!! - {parent.toBasicString()}");
foreach (var item_base in has_items)
{
var item = item_base as Item;
NullReferenceCheckHelper.throwIfNull(item, () => $"item is null !!! - {parent.toBasicString()}");
var item_meta_id = item.getItemMetaId();
UInt16 item_stack_count = item.getItemStackCount();
foreach (var find_item_meta_id in itemMetaIds)
{
if(find_item_meta_id == item_meta_id)
{
if(found_items.TryGetValue(item_meta_id, out UInt16 item_count) == false)
{
found_items.TryAdd(item_meta_id, item_stack_count);
break;
}
found_items[item_meta_id] = (ushort)(item_count + item_stack_count);
break;
}
}
}
return found_items;
}
public Int32 getItemStackCountAllByMetaId(META_ID itemMetaId)
{
var parent = getDirectParent();
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!!");
var item_stack_count_all = 0;
var has_items = getHasItemBases();
NullReferenceCheckHelper.throwIfNull(has_items, () => $"has_items is null !!! - {parent.toBasicString()}");
foreach (var item in has_items)
{
var item_meta = item.getItemMeta();
NullReferenceCheckHelper.throwIfNull(item_meta, () => $"item_meta is null !!! - {parent.toBasicString()}");
if (item_meta.ItemId != itemMetaId)
{
continue;
}
item_stack_count_all += item.getItemStackCount();
}
return item_stack_count_all;
}
public Int32 getItemCountAllByMetaId(META_ID itemMetaId)
{
var parent = getDirectParent();
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!!");
var item_count_all = 0;
var has_items = getHasItemBases();
NullReferenceCheckHelper.throwIfNull(has_items, () => $"has_items is null !!! - {parent.toBasicString()}");
foreach (var item in has_items)
{
var item_meta = item.getItemMeta();
NullReferenceCheckHelper.throwIfNull(item_meta, () => $"item_meta is null !!! - {parent.toBasicString()}");
if (item_meta.ItemId != itemMetaId)
{
continue;
}
item_count_all += 1;
}
return item_count_all;
}
public List<Item> getItemAllByMetaId(META_ID itemMetaId)
{
var parent = getDirectParent();
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!!");
var found_items = new List<Item>();
var has_items = getHasItemBases();
NullReferenceCheckHelper.throwIfNull(has_items, () => $"has_items is null !!! - {parent.toBasicString()}");
foreach (var item_base in has_items)
{
var item = item_base as Item;
NullReferenceCheckHelper.throwIfNull(item, () => $"item is null !!! - {parent.toBasicString()}");
var item_meta = item.getItemMeta();
NullReferenceCheckHelper.throwIfNull(item_meta, () => $"item_meta is null !!! - {parent.toBasicString()}");
if (item_meta.ItemId != itemMetaId)
{
continue;
}
found_items.Add(item);
}
return found_items;
}
public override void onWriteLog()
{
var parent = getDirectParent();
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!!");
var err_msg = string.Empty;
var total_count = 0;
var total_max_count = 0;
foreach(var each in m_bag_tab_take_in_counts)
{
var bag_tab_type = each.Key;
var bag_tab = each.Value;
err_msg = $"BagTabType:{bag_tab_type}, TakeInCount:{bag_tab.TakeInItemCount}, SlotMaxCount:{bag_tab.getSlotMaxCount()}";
Log.getLogger().info(err_msg);
total_count += bag_tab.TakeInItemCount;
total_max_count += bag_tab.getSlotMaxCount();
}
var has_items = getHasItemBases();
NullReferenceCheckHelper.throwIfNull(has_items, () => $"has_items is null !!! - {parent.toBasicString()}");
err_msg = $"BagTab TotalTakeInCount:{total_count}, TotalSlotMaxCount:{total_max_count}, TotalItemCount:{has_items.Count}";
Log.getLogger().info(err_msg);
}
public async Task<Result> tryCheckTakableInBagInven(Dictionary<META_ID, Int16> toCheckTakableInItemCounts)
{
var parent = getDirectParent();
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!!");
NullReferenceCheckHelper.throwIfNull(toCheckTakableInItemCounts, () => $"toCheckTakableInItemCounts is null !!! - {parent.toBasicString()}");
var result = new Result();
var err_msg = string.Empty;
bool is_found_value = (false == toCheckTakableInItemCounts.Any()) || toCheckTakableInItemCounts.Values.All(value => value <= 0);
if(true == is_found_value)
{
return result;
}
var server_logic = GameServerApp.getServerLogic();
NullReferenceCheckHelper.throwIfNull(server_logic, () => $"server_logic is null !!! - {parent.toBasicString()}");
var inventory_rule = server_logic.findRule<InventoryRule>();
NullReferenceCheckHelper.throwIfNull(inventory_rule, () => $"inventory_rule is null !!! - {parent.toBasicString()}");
var is_found_target_bag_tab = false;
foreach (var each in toCheckTakableInItemCounts)
{
var item_meta_id = each.Key;
var item_count = each.Value;
// 1. 아이템 메타 정보를 얻는다.
if (false == MetaData.Instance._ItemTable.TryGetValue((Int32)item_meta_id, out var found_item_meta))
{
err_msg = $"Not found Item Meta !!! : itemMetaId:{item_meta_id} - {parent.toBasicString()}";
result.setFail(ServerErrorCode.ItemMetaDataNotFound, err_msg);
Log.getLogger().error(result.toBasicString());
return result;
}
// 2. 동일한 종류의 ItemAttributeBase 목록과 보유 개수를 얻는다.
(result, var target_item_attributes, var item_has_count) = findItemAttributeBaseAllByMetaId(item_meta_id, (ushort)item_count);
if (result.isFail())
{
return result;
}
var remain_count = item_count;
target_item_attributes.OrderByDescending(x => { return x.ItemStackCount; });
// 3. 동일한 종류의 아이템에 최대 Stack 개수이내로 추가 한다.
foreach (var item_attribute in target_item_attributes)
{
if (remain_count <= 0)
{
break;
}
var max_count = found_item_meta.StackMaxCount;
var to_modify_item = item_attribute.getOwner() as Item;
NullReferenceCheckHelper.throwIfNull(to_modify_item, () => $"to_modify_item is null !!! - {parent.toBasicString()}");
var to_modify_item_attribute = to_modify_item.getEntityAttribute<ItemAttributeBase>();
NullReferenceCheckHelper.throwIfNull(to_modify_item_attribute, () => $"to_modify_item_attribute is null !!! - {parent.toBasicString()}");
var has_count = to_modify_item_attribute.ItemStackCount;
if (has_count >= found_item_meta.StackMaxCount)
{
continue;
}
var to_add_count = 0;
if (has_count + remain_count > max_count)
{
to_add_count = max_count - has_count;
}
else
{
to_add_count = remain_count;
}
remain_count -= (short)to_add_count;
is_found_target_bag_tab = true;
}
if (0 < remain_count)
{
is_found_target_bag_tab = false;
var to_inc_slot_count = remain_count / found_item_meta.StackMaxCount;
to_inc_slot_count += ((remain_count % found_item_meta.StackMaxCount) > 0 ? 1 : 0);
var found_bag_rules = inventory_rule.getBagRulesByItemLargeType(found_item_meta.TypeLarge);
NullReferenceCheckHelper.throwIfNull(found_bag_rules, () => $"found_bag_rules is null !!! - {parent.toBasicString()}");
foreach (var bag_rule in found_bag_rules)
{
var target_bag_type = bag_rule.InvenBagType;
var usable_bag_tab_type = target_bag_type.toUsableBagTabType().toNFTTabOffset(found_item_meta);
if (true == m_bag_tab_take_in_counts.TryGetValue(usable_bag_tab_type, out var found_tab))
{
is_found_target_bag_tab = true;
// 슬롯에 예약된 아이템 개수까지 확인하여 보관 가능 여부를 체크 한다.
var reserved_count = 0;
// Transaction 활성화 상태일 경우
var transaction_runner = parent.findTransactionRunner(TransactionIdType.PrivateContents);
if (null != transaction_runner)
{
var found_reserved_slot = transaction_runner.findReservedSlot(parent, getEntityType(), usable_bag_tab_type.convertEnumToEnumTypeAndValueString());
if (null != found_reserved_slot)
{
reserved_count += found_reserved_slot.getReservedCount();
}
}
if (false == found_tab.tryCheckTakableInItem((Int16)to_inc_slot_count, (Int16)reserved_count))
{
err_msg = $"Failed to tryCheckTakableInItem() !!!, Bag is reserved item full : incSlotCount:{remain_count}, reservedSlotCount:{reserved_count}"
+ $" - itemMetaId:{item_meta_id}, usableInvenBagName:{usable_bag_tab_type.toUsableInvenBagName()}, {parent.toBasicString()}";
result.setFail(ServerErrorCode.BagIsReservedItemFull, err_msg);
Log.getLogger().error(result.toBasicString());
return result;
}
}
}
}
}
if(false == is_found_target_bag_tab)
{
err_msg = $"Not found target BagTab !!! - {parent.toBasicString()}";
result.setFail(ServerErrorCode.BagTabTypeNotFound, err_msg);
Log.getLogger().error(result.toBasicString());
return result;
}
return await Task.FromResult(result);
}
public ConcurrentDictionary<BagTabType, BagTab> getBagTabs() => m_bag_tab_take_in_counts;
public override string toSummaryString()
{
return $"{this.getTypeName()}, {getData().toBasicString()}";
}
}
}