Files
caliverse_server/ServerCommon/Entity/Inventory/InventoryBase.cs
2025-05-01 07:20:41 +09:00

353 lines
14 KiB
C#

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ServerCore; using ServerBase;
using MetaAssets;
using SESSION_ID = System.Int32;
using WORLD_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 Google.Protobuf.WellKnownTypes;
namespace ServerCommon;
public abstract class InventoryBase<TSlotType> : SlotsWrapperBase<SlotsWithEntityBase<TSlotType>>, IWithInventoryAccessor
where TSlotType : notnull
{
public InventoryBase(EntityType entityType, EntityBase parent)
: base(entityType, parent)
{
}
public virtual Result onTryTakeInEntityBase(TSlotType entityGuid, EntityBase toTakeInEntityBase)
{
var err_msg = string.Empty;
var result = tryIsEquipableOrEquipWithEntityBase(entityGuid, toTakeInEntityBase);
if (result.isFail())
{
err_msg = $"Failed to onTryIsEquipableOrEquipWithEntityBase() !!! : {result.toBasicString()}";
Log.getLogger().error(err_msg);
return result;
}
return result;
}
public virtual Result onTryTakeOutEnityBase(ENTITY_GUID entityGuid, out EntityBase? takenOutEntityBase)
{
var err_msg = string.Empty;
takenOutEntityBase = null;
var result = tryUnequipableOrUnequipWithEntityBase(entityGuid, out var taken_out_entity_base);
if (result.isFail())
{
err_msg = $"Failed to onTryUnequipableOrUnequipWithEntityBase() !!! : {result.toBasicString()}";
Log.getLogger().error(err_msg);
return result;
}
takenOutEntityBase = taken_out_entity_base;
return result;
}
public (Result, List<ItemAttributeBase>, UInt16) findItemAttributeBaseAllByMetaId(META_ID itemMetaId, UInt32 toCheckItemCount = UInt32.MaxValue)
{
var parent = getDirectParent();
NullReferenceCheckHelper.throwIfNull(parent, () => $"paren is null !!!");
var inven_data = getData();
NullReferenceCheckHelper.throwIfNull(inven_data, () => $"inven_data is null !!! - {parent.toBasicString()}");
var err_msg = string.Empty;
var result = new Result();
var target_item_attributes = new List<ItemAttributeBase>();
if (0 >= itemMetaId)
{
err_msg = $"Invalid ItemMetaId !!! : itemMetaId:{itemMetaId} > 0 - {parent.toBasicString()}";
result.setFail(ServerErrorCode.MetaIdInvalid, err_msg);
Log.getLogger().error(result.toBasicString());
return (result, target_item_attributes, 0);
}
// 1. 아이템 메타 정보를 얻는다.
if (false == MetaData.Instance._ItemTable.TryGetValue((int)itemMetaId, out var itemMetaData))
{
err_msg = $"Not found ItemMeta !!! : itemMetaId:{itemMetaId} - {parent.toBasicString()}";
result.setFail(ServerErrorCode.ItemMetaDataNotFound, err_msg);
Log.getLogger().error(result.toBasicString());
return (result, target_item_attributes, 0);
}
// 2. 동일한 종류의 현재 Origin ItemAttributeBase 목록을 얻는다.
var found_origin_item_attributes = getHasSlotsWithEntityBases().Where(x =>
{
var item_attribute_base = x.Value.getOriginEntityAttribute<ItemAttributeBase>();
NullReferenceCheckHelper.throwIfNull(item_attribute_base, () => $"item_attribute_base is null !!! - {parent.toBasicString()}");
if ( item_attribute_base.ItemMetaId == itemMetaId
&& item_attribute_base.ItemStackCount > 0)
{
return true;
}
return false;
}).Select(x =>
{
var item_attribute_base = x.Value.getOriginEntityAttribute<ItemAttributeBase>();
NullReferenceCheckHelper.throwIfNull(item_attribute_base, () => $"item_attribute_base is null !!! - {parent.toBasicString()}");
return (item_attribute_base.ItemGuid, item_attribute_base);
}).ToDictionary();
// 3. 동일한 종류의 예약된 Cloned ItemAttributeBase 목록을 얻는다.
var found_cloned_item_attributes = new Dictionary<ITEM_GUID, ItemAttributeBase>();
var found_transaction_runner = parent.findTransactionRunner(TransactionIdType.PrivateContents);
if (null != found_transaction_runner)
{
var entity_attribute_transactors = found_transaction_runner.getEntityAttributeTransactorAll(parent.onGetAvailableItemAttributeType());
found_cloned_item_attributes = entity_attribute_transactors.Where(x =>
{
var item_attribute_base = x.Value.getClonedEntityAttribute() as ItemAttributeBase;
NullReferenceCheckHelper.throwIfNull(item_attribute_base, () => $"item_attribute_base is null !!! - {parent.toBasicString()}");
if ( item_attribute_base.ItemMetaId == itemMetaId
&& item_attribute_base.ItemStackCount >= 0 )
{
return true;
}
return false;
}).Select(x =>
{
var item_attribute = x.Value.getClonedEntityAttribute() as ItemAttributeBase;
NullReferenceCheckHelper.throwIfNull(item_attribute, () => $"item_attribute is null !!! - {parent.toBasicString()}");
return (item_attribute.ItemGuid, item_attribute);
}).ToDictionary();
}
// 4. Cloned 정보가 있거나, Origin 정보만 있는 경우 대상 아이템으로 추가한다 !!!
var all_keys = found_origin_item_attributes.Keys.Concat(found_cloned_item_attributes.Keys).Distinct();
foreach (var key in all_keys)
{
// 4.1. Cloned 정보가 있는데, 삭제 대상일 경우는 Origin & Cloned 모두 무시 한다.
if(true == found_cloned_item_attributes.TryGetValue(key, out var found_cloned_attribute))
{
var stack_count = found_cloned_attribute.ItemStackCount;
if (0 >= stack_count)
{
// 4.1.1. Cloned 정보가 삭제 대상일 경우 추가하지 않는다. (삭제될거니까...)
continue;
}
else
{
// 4.1.2. Cloned 정보의 아이템 개수가 존재 한다면 추가 한다.
target_item_attributes.Add(found_cloned_attribute);
}
}
// 4.2. Origin 정보만 있는 경우 추가 한다.
else if (found_origin_item_attributes.ContainsKey(key) && false == found_cloned_item_attributes.ContainsKey(key))
{
var only_origin_item_attribute = found_origin_item_attributes[key];
target_item_attributes.Add(only_origin_item_attribute);
}
}
// 5. 조건에 총족된 대상 아이템들의 StackCount 합산 개수를 얻는다.
var item_has_count = target_item_attributes.Sum(x => {
return x.ItemStackCount;
});
return (result, target_item_attributes, (UInt16)item_has_count);
}
public EntityBase? findEntityBase(TSlotType toFindEntityBaseKey)
{
var parent = getDirectParent();
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!!");
var inven_data = getData();
NullReferenceCheckHelper.throwIfNull(inven_data, () => $"inven_data is null !!! - {parent.toBasicString()}");
var found_entity_base = inven_data.findEntityBaseInSlotType(toFindEntityBaseKey);
if (null == found_entity_base)
{
return null;
}
return found_entity_base;
}
public override void onWriteLog()
{
var parent = getDirectParent();
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!!");
var has_items = getHasSlotsWithEntityBases();
NullReferenceCheckHelper.throwIfNull(has_items, () => $"has_items is null !!! - {parent.toBasicString()}");
foreach (var each in has_items)
{
var slot_type = each.Key;
META_ID item_meta_id = 0;
var item_guid = string.Empty;
var item_stack_count = 0;
var item_max_stack_count = 0;
var item_base = each.Value as ItemBase;
if (null != item_base)
{
var item_attibute_base = item_base.getEntityAttribute<ItemAttributeBase>();
NullReferenceCheckHelper.throwIfNull(item_attibute_base, () => $"item_attibute_base is null !!!");
item_meta_id = (META_ID)item_attibute_base.ItemMetaId;
item_guid = item_attibute_base.ItemGuid;
item_stack_count = item_attibute_base.ItemStackCount;
if (true == MetaData.Instance._ItemTable.TryGetValue((int)item_meta_id, out var found_item_meta))
{
item_max_stack_count = found_item_meta.StackMaxCount;
}
}
var err_msg = $"SlotType:{slot_type}, ItemMetaId:{item_meta_id}, StackCount:{item_stack_count}, MaxStackCount:{item_max_stack_count}, ItemGuid:{item_guid}";
Log.getLogger().info(err_msg);
}
}
public ConcurrentDictionary<TSlotType, EntityBase> getHasSlotsWithEntityBases()
{
var parent = getDirectParent();
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!!");
var inven_data = getData();
NullReferenceCheckHelper.throwIfNull(inven_data, () => $"inven_data is null !!! - {parent.toBasicString()}");
var slots = inven_data.getSlots() as ConcurrentDictionary<TSlotType, EntityBase>;
NullReferenceCheckHelper.throwIfNull(slots, () => $"slots is null !!! - {parent.toBasicString()}");
return slots;
}
public List<EntityBase> getHasEntityBases()
{
var parent = getDirectParent();
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!!");
var inven_data = getData();
NullReferenceCheckHelper.throwIfNull(inven_data, () => $"inven_data is null !!! - {parent.toBasicString()}");
var slots_with_entity_bases = getHasSlotsWithEntityBases();
NullReferenceCheckHelper.throwIfNull(slots_with_entity_bases, () => $"slots_with_entity_bases is null !!! - {parent.toBasicString()}");
return slots_with_entity_bases.Select(x => x.Value).ToList();
}
// IWithInventoryAccessor.clearItemAll()
public void clearItemAll()
{
var parent = getDirectParent();
NullReferenceCheckHelper.throwIfNull(parent, () => $"paren is null !!!");
var inven_data = getData();
NullReferenceCheckHelper.throwIfNull(inven_data, () => $"inven_data is null !!! - {parent.toBasicString()}");
var slots = inven_data.getSlots() as ConcurrentDictionary<TSlotType, EntityBase>;
NullReferenceCheckHelper.throwIfNull(slots, () => $"slots is null !!! - {parent.toBasicString()}");
slots.Clear();
}
// IWithInventoryAccessor.getHasItemBases()
public List<ItemBase> getHasItemBases()
{
var parent = getDirectParent();
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!!");
return getHasSlotsWithEntityBases().Select(x =>
{
var item_base = x.Value as ItemBase;
NullReferenceCheckHelper.throwIfNull(item_base, () => $"item_base is null !!! - {parent.toBasicString()}");
return item_base;
}).ToList();
}
// IWithInventoryAccessor.tryEquipWithItemBase()
public ServerErrorCode tryEquipWithItemBase(string slotType, ItemBase itemBase)
{
var parent = getDirectParent();
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!!");
var inven_data = getData();
NullReferenceCheckHelper.throwIfNull(inven_data, () => $"inven_data is null !!! - {parent.toBasicString()}");
var err_msg = string.Empty;
if(false == slotType.fillupEnumTypeAndValueStringToEnum<TSlotType>("None", out var target_slot_type) || null == target_slot_type)
{
err_msg = $"Failed to fillupEnumTypeAndValueStringToEnum<TSlotType>() !!!, SlotType of Target Inventory : targetSlotType:{slotType} - {parent.toBasicString()}";
Log.getLogger().error(err_msg);
return ServerErrorCode.StringConvertToEnumFailed;
}
return inven_data.onTryEquipWithEntityBase(target_slot_type, itemBase);
}
// IWithInventoryAccessor.tryUnequipWithItemBase()
public ServerErrorCode tryUnequipWithItemBase(string slotType, out ItemBase? itemBase)
{
itemBase = null;
var parent = getDirectParent();
NullReferenceCheckHelper.throwIfNull(parent, () => $"parent is null !!!");
var inven_data = getData();
NullReferenceCheckHelper.throwIfNull(inven_data, () => $"inven_data is null !!! - {parent.toBasicString()}");
var err_msg = string.Empty;
if (false == slotType.fillupEnumTypeAndValueStringToEnum<TSlotType>("None", out var target_slot_type) || null == target_slot_type)
{
err_msg = $"Failed to fillupEnumTypeAndValueStringToEnum<TSlotType>() !!!, SlotType of Target Inventory : targetSlotType:{slotType} - {parent.toBasicString()}";
Log.getLogger().error(err_msg);
return ServerErrorCode.StringConvertToEnumFailed;
}
var result_code = inven_data.onTryUnequipWithEntityBase(target_slot_type, out EntityBase? entity_base);
if (ServerErrorCode.Success == result_code)
{
itemBase = entity_base as ItemBase;
}
return result_code;
}
}