719 lines
No EOL
34 KiB
C#
719 lines
No EOL
34 KiB
C#
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using PhoenixLib.Caching;
|
|
using PhoenixLib.Logging;
|
|
using WingsAPI.Communication.Bazaar;
|
|
using WingsAPI.Data.Bazaar;
|
|
using WingsAPI.Data.GameData;
|
|
using WingsAPI.Game.Extensions.Bazaar;
|
|
using WingsAPI.Packets.Enums.Bazaar;
|
|
using WingsAPI.Packets.Enums.Bazaar.Filter;
|
|
using WingsAPI.Packets.Enums.Bazaar.SubFilter;
|
|
using WingsEmu.Core.Generics;
|
|
using WingsEmu.DTOs.Items;
|
|
using WingsEmu.Game._enum;
|
|
using WingsEmu.Packets.Enums;
|
|
using WingsEmu.Packets.Enums.Battle;
|
|
using WingsEmu.Packets.Enums.Character;
|
|
|
|
namespace BazaarServer.Managers
|
|
{
|
|
public class BazaarSearchManager
|
|
{
|
|
private readonly ILongKeyCachedRepository<ConcurrentDictionary<long, BazaarItemDTO>> _bazaarItemByItemVnum;
|
|
private readonly ILongKeyCachedRepository<(ItemDTO, BazaarLevelFilterType)> _cachedItems;
|
|
private readonly IResourceLoader<ItemDTO> _itemDao;
|
|
|
|
private readonly Dictionary<BazaarCategoryFilterType, Dictionary<byte, HashSet<int>>> _itemVnumByCategoryAndSubCategory = new();
|
|
|
|
private readonly ThreadSafeHashSet<int> _itemVnumsRegistered = new();
|
|
|
|
public BazaarSearchManager(ILongKeyCachedRepository<ConcurrentDictionary<long, BazaarItemDTO>> bazaarItemByItemVnum, IResourceLoader<ItemDTO> itemDao,
|
|
ILongKeyCachedRepository<(ItemDTO, BazaarLevelFilterType)> cachedItems)
|
|
{
|
|
_bazaarItemByItemVnum = bazaarItemByItemVnum;
|
|
_itemDao = itemDao;
|
|
_cachedItems = cachedItems;
|
|
}
|
|
|
|
public async Task Initialize(IEnumerable<BazaarItemDTO> bazaarItemDtos)
|
|
{
|
|
await CategorizeItems();
|
|
await CacheSearchableBazaarItems(bazaarItemDtos);
|
|
}
|
|
|
|
private async Task CacheSearchableBazaarItems(IEnumerable<BazaarItemDTO> bazaarItemDtos)
|
|
{
|
|
Log.Info("[BAZAAR_SEARCH_MANAGER] Caching searchable BazaarItems");
|
|
int count = 0;
|
|
foreach (BazaarItemDTO bazaarItemDto in bazaarItemDtos)
|
|
{
|
|
if (bazaarItemDto.GetBazaarItemStatus() != BazaarListedItemType.ForSale)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
AddItem(bazaarItemDto);
|
|
count++;
|
|
}
|
|
|
|
Log.Info($"[BAZAAR_SEARCH_MANAGER] Cached: {count} searchable BazaarItems");
|
|
}
|
|
|
|
private async Task CategorizeItems()
|
|
{
|
|
Log.Info("[BAZAAR_SEARCH_MANAGER] Categorizing items from DB");
|
|
IEnumerable<ItemDTO> items = await _itemDao.LoadAsync();
|
|
|
|
int count = 0;
|
|
var itemsToRegister = new Dictionary<BazaarCategoryFilterType, HashSet<int>>();
|
|
foreach (ItemDTO item in items)
|
|
{
|
|
(BazaarCategoryFilterType category, IEnumerable<byte> subCategories, bool registerForAllSubcategories) = GetCategoryAndSubCategoriesByItemVnum(item);
|
|
if (registerForAllSubcategories && !itemsToRegister.TryAdd(category, new HashSet<int> { item.Id }))
|
|
{
|
|
itemsToRegister[category].Add(item.Id);
|
|
}
|
|
|
|
if (!_itemVnumByCategoryAndSubCategory.ContainsKey(category))
|
|
{
|
|
_itemVnumByCategoryAndSubCategory.Add(category, new Dictionary<byte, HashSet<int>>());
|
|
}
|
|
|
|
foreach (byte subCategory in subCategories)
|
|
{
|
|
if (!_itemVnumByCategoryAndSubCategory[category].ContainsKey(subCategory))
|
|
{
|
|
_itemVnumByCategoryAndSubCategory[category].Add(subCategory, new HashSet<int>());
|
|
}
|
|
|
|
_itemVnumByCategoryAndSubCategory[category][subCategory].Add(item.Id);
|
|
}
|
|
|
|
|
|
if (!_itemVnumByCategoryAndSubCategory[category].ContainsKey(0))
|
|
{
|
|
_itemVnumByCategoryAndSubCategory[category].Add(0, new HashSet<int>());
|
|
}
|
|
|
|
_itemVnumByCategoryAndSubCategory[category][0].Add(item.Id);
|
|
|
|
_cachedItems.Set(item.Id, (item, GetItemLevelFilterByLevel(item.LevelMinimum, item.IsHeroic)));
|
|
count++;
|
|
}
|
|
|
|
foreach (KeyValuePair<BazaarCategoryFilterType, HashSet<int>> itemToRegister in itemsToRegister)
|
|
{
|
|
Type type = GetSubCategoryTypeByCategory(itemToRegister.Key);
|
|
if (type == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
foreach (byte value in Enum.GetValues(type))
|
|
{
|
|
if (!_itemVnumByCategoryAndSubCategory[itemToRegister.Key].ContainsKey(value))
|
|
{
|
|
_itemVnumByCategoryAndSubCategory[itemToRegister.Key].Add(value, new HashSet<int>());
|
|
}
|
|
|
|
foreach (int vnum in itemToRegister.Value)
|
|
{
|
|
_itemVnumByCategoryAndSubCategory[itemToRegister.Key][value].Add(vnum);
|
|
}
|
|
}
|
|
}
|
|
|
|
Log.Info($"[BAZAAR_SEARCH_MANAGER] Categorized: {count.ToString()} items");
|
|
}
|
|
|
|
private static Type GetSubCategoryTypeByCategory(BazaarCategoryFilterType category)
|
|
{
|
|
switch (category)
|
|
{
|
|
case BazaarCategoryFilterType.Specialist:
|
|
return typeof(BazaarCategorySpecialistSubFilterType);
|
|
case BazaarCategoryFilterType.Partner:
|
|
return typeof(BazaarCategoryPartnerSubFilterType);
|
|
case BazaarCategoryFilterType.Pet:
|
|
return typeof(BazaarCategoryPetSubFilterType);
|
|
case BazaarCategoryFilterType.StoreMount:
|
|
return typeof(BazaarCategoryConsumerItemSubFilterType);
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public void AddItem(BazaarItemDTO bazaarItemDto)
|
|
{
|
|
ItemInstanceDTO itemInstanceDto = bazaarItemDto?.ItemInstance;
|
|
if (itemInstanceDto == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
ConcurrentDictionary<long, BazaarItemDTO> dictionary = _bazaarItemByItemVnum.GetOrSet(itemInstanceDto.ItemVNum, () => new ConcurrentDictionary<long, BazaarItemDTO>());
|
|
dictionary[bazaarItemDto.Id] = bazaarItemDto;
|
|
_itemVnumsRegistered.Add(itemInstanceDto.ItemVNum);
|
|
}
|
|
|
|
public void RemoveItem(BazaarItemDTO bazaarItemDto)
|
|
{
|
|
if (bazaarItemDto == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
ConcurrentDictionary<long, BazaarItemDTO> dictionary = _bazaarItemByItemVnum.GetOrSet(bazaarItemDto.ItemInstance.ItemVNum, () => new ConcurrentDictionary<long, BazaarItemDTO>());
|
|
dictionary.Remove(bazaarItemDto.Id, out _);
|
|
if (!dictionary.IsEmpty)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_bazaarItemByItemVnum.Remove(bazaarItemDto.ItemInstance.ItemVNum);
|
|
_itemVnumsRegistered.Remove(bazaarItemDto.ItemInstance.ItemVNum);
|
|
}
|
|
|
|
public IReadOnlyCollection<BazaarItemDTO> SearchBazaarItems(BazaarSearchContext bazaarSearchContext)
|
|
{
|
|
IReadOnlyCollection<int> desiredItemVNums =
|
|
(bazaarSearchContext.ItemVNumFilter ?? GetItemVNumsByCategoryAndSubCategory(bazaarSearchContext.CategoryFilterType, bazaarSearchContext.SubTypeFilter)) ??
|
|
_itemVnumsRegistered.ToArray();
|
|
|
|
var itemList = new List<BazaarItemDTO>();
|
|
var tempItemList = new List<BazaarItemDTO>();
|
|
|
|
int ignoreCounter = bazaarSearchContext.Index * bazaarSearchContext.AmountOfItemsPerIndex;
|
|
int sendCounter = 0;
|
|
|
|
foreach (int itemVnum in desiredItemVNums.OrderBy(x => x))
|
|
{
|
|
ConcurrentDictionary<long, BazaarItemDTO> dictionary = _bazaarItemByItemVnum.Get(itemVnum);
|
|
if (dictionary == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (ignoreCounter > dictionary.Count && bazaarSearchContext.LevelFilter == BazaarLevelFilterType.All && bazaarSearchContext.RareFilter == BazaarRarityFilterType.All &&
|
|
bazaarSearchContext.UpgradeFilter == BazaarUpgradeFilterType.All)
|
|
{
|
|
ignoreCounter -= dictionary.Count;
|
|
continue;
|
|
}
|
|
|
|
(ItemDTO itemDto, BazaarLevelFilterType baseItemLevelFilter) = _cachedItems.Get(itemVnum);
|
|
|
|
bool itemLevelIsInstanceDependant = false;
|
|
if (baseItemLevelFilter == BazaarLevelFilterType.All)
|
|
{
|
|
itemLevelIsInstanceDependant = true;
|
|
}
|
|
else
|
|
{
|
|
if (bazaarSearchContext.LevelFilter != BazaarLevelFilterType.All && !ItemLevelFilterChecker(bazaarSearchContext.LevelFilter, baseItemLevelFilter))
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
IOrderedEnumerable<KeyValuePair<long, BazaarItemDTO>> values;
|
|
switch (bazaarSearchContext.OrderFilter)
|
|
{
|
|
case BazaarSortFilterType.PriceAscending:
|
|
values = dictionary.OrderBy(x => x.Value.PricePerItem);
|
|
break;
|
|
case BazaarSortFilterType.PriceDescending:
|
|
values = dictionary.OrderByDescending(x => x.Value.PricePerItem);
|
|
break;
|
|
case BazaarSortFilterType.AmountAscending:
|
|
values = dictionary.OrderBy(x => x.Value.Amount - x.Value.SoldAmount);
|
|
break;
|
|
case BazaarSortFilterType.AmountDescending:
|
|
values = dictionary.OrderByDescending(x => x.Value.Amount - x.Value.SoldAmount);
|
|
break;
|
|
default:
|
|
return null;
|
|
}
|
|
|
|
foreach ((long _, BazaarItemDTO bazaarItemDto) in values)
|
|
{
|
|
BazaarListedItemType itemStatus = bazaarItemDto.GetBazaarItemStatus();
|
|
if (itemStatus != BazaarListedItemType.ForSale)
|
|
{
|
|
RemoveItem(bazaarItemDto);
|
|
continue;
|
|
}
|
|
|
|
if (bazaarItemDto.ItemInstance.Type == ItemInstanceType.BoxInstance)
|
|
{
|
|
BazaarPerfectionFilterType itemRarityFilter = GetPerfectionFilterByInstance(bazaarItemDto.ItemInstance);
|
|
|
|
if ((int)bazaarSearchContext.RareFilter != (int)BazaarPerfectionFilterType.All && (int)itemRarityFilter != (int)bazaarSearchContext.RareFilter)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
BazaarRarityFilterType itemRarityFilter = GetRarityFilterByInstance(bazaarItemDto.ItemInstance);
|
|
|
|
if (bazaarSearchContext.RareFilter != BazaarRarityFilterType.All && itemRarityFilter != bazaarSearchContext.RareFilter)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
BazaarUpgradeFilterType itemUpgradeFilter = GetUpgradeFilterByInstance(bazaarItemDto.ItemInstance);
|
|
|
|
if (bazaarSearchContext.UpgradeFilter != BazaarUpgradeFilterType.All && itemUpgradeFilter != bazaarSearchContext.UpgradeFilter)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (itemLevelIsInstanceDependant)
|
|
{
|
|
BazaarLevelFilterType itemLevelFilter = GetItemLevelFilterByInstance(bazaarItemDto.ItemInstance, bazaarItemDto.ItemInstance.Type);
|
|
|
|
if (bazaarSearchContext.LevelFilter != BazaarLevelFilterType.All && itemLevelFilter != bazaarSearchContext.LevelFilter)
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (bazaarSearchContext.SubTypeFilter != 0 && bazaarItemDto.ItemInstance.Type == ItemInstanceType.BoxInstance)
|
|
{
|
|
if ((UsableItemSubType)itemDto.ItemSubType != UsableItemSubType.RaidBoxOrSealedJajamaruSpOrSealedSakuraBead)
|
|
{
|
|
ItemInstanceDTO boxInstanceDto = bazaarItemDto.ItemInstance;
|
|
|
|
if (!GetBoxInstanceSubCategories(boxInstanceDto, itemDto).Contains(bazaarSearchContext.SubTypeFilter))
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ignoreCounter > 0)
|
|
{
|
|
ignoreCounter--;
|
|
continue;
|
|
}
|
|
|
|
if (sendCounter >= bazaarSearchContext.AmountOfItemsPerIndex)
|
|
{
|
|
break;
|
|
}
|
|
|
|
sendCounter++;
|
|
|
|
tempItemList.Add(bazaarItemDto);
|
|
}
|
|
|
|
itemList.AddRange(tempItemList);
|
|
tempItemList.Clear();
|
|
|
|
if (sendCounter >= bazaarSearchContext.AmountOfItemsPerIndex)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return itemList;
|
|
}
|
|
|
|
private List<byte> GetBoxInstanceSubCategories(ItemInstanceDTO boxInstanceDto, ItemDTO itemInfo)
|
|
{
|
|
var subCategory = new List<byte>();
|
|
switch ((UsableItemSubType)itemInfo.ItemSubType)
|
|
{
|
|
case UsableItemSubType.PetBead:
|
|
subCategory.Add(
|
|
(byte)(boxInstanceDto.HoldingVNum is 0 or null ? BazaarCategoryPetSubFilterType.EmptyPetBead : BazaarCategoryPetSubFilterType.PetBead));
|
|
break;
|
|
case UsableItemSubType.PartnerBead:
|
|
if (boxInstanceDto.HoldingVNum is 0 or null)
|
|
{
|
|
subCategory.Add((byte)BazaarCategoryPartnerSubFilterType.EmptyPartnerBead);
|
|
break;
|
|
}
|
|
|
|
subCategory.Add((byte)BazaarCategoryPartnerSubFilterType.PartnerBead);
|
|
subCategory.Add((byte)GetPartnerSubCategoryOfAttack(_cachedItems.Get(boxInstanceDto.HoldingVNum.Value).Item1));
|
|
break;
|
|
case UsableItemSubType.PartnerSpHolder:
|
|
if (boxInstanceDto.HoldingVNum is 0 or null)
|
|
{
|
|
subCategory.Add((byte)BazaarCategoryPartnerSubFilterType.EmptyCardHolder);
|
|
break;
|
|
}
|
|
|
|
subCategory.Add((byte)GetPartnerSubCategoryOfAttack(_cachedItems.Get(boxInstanceDto.HoldingVNum.Value).Item1));
|
|
break;
|
|
case UsableItemSubType.SpecialistHolder:
|
|
if (boxInstanceDto.HoldingVNum is 0 or null)
|
|
{
|
|
subCategory.Add((byte)BazaarCategorySpecialistSubFilterType.EmptyCardHolder);
|
|
break;
|
|
}
|
|
|
|
subCategory.Add(SpMorphToSubCategory(_cachedItems.Get(boxInstanceDto.HoldingVNum.Value).Item1));
|
|
break;
|
|
case UsableItemSubType.VehicleBead:
|
|
subCategory.Add((byte)(boxInstanceDto.HoldingVNum is 0 or null ? BazaarCategoryStoreMountSubFilterType.EmptyMountBead : BazaarCategoryStoreMountSubFilterType.MountBead));
|
|
break;
|
|
}
|
|
|
|
return subCategory;
|
|
}
|
|
|
|
private (BazaarCategoryFilterType, IEnumerable<byte>, bool) GetCategoryAndSubCategoriesByItemVnum(ItemDTO itemDto)
|
|
{
|
|
BazaarCategoryFilterType category = BazaarCategoryFilterType.Miscellaneous;
|
|
var subCategories = new List<byte>();
|
|
bool registerForAllSubcategories = false;
|
|
switch (itemDto.ItemType)
|
|
{
|
|
case ItemType.Weapon:
|
|
category = BazaarCategoryFilterType.Weapon;
|
|
subCategories.Add(ItemTypeClassToSubCategory(itemDto.Class));
|
|
break;
|
|
case ItemType.Armor:
|
|
category = BazaarCategoryFilterType.Armour;
|
|
subCategories.Add(ItemTypeClassToSubCategory(itemDto.Class));
|
|
break;
|
|
case ItemType.Fashion:
|
|
category = BazaarCategoryFilterType.Equipment;
|
|
subCategories.Add(EquipmentTypeToSubCategory1(itemDto.EquipmentSlot));
|
|
byte? secondSubCategory = EquipmentTypeToSubCategory2(itemDto.EquipmentSlot, itemDto.Sex switch
|
|
{
|
|
0 => GenderType.Unisex,
|
|
1 => GenderType.Male,
|
|
_ => GenderType.Female
|
|
});
|
|
if (secondSubCategory != null)
|
|
{
|
|
subCategories.Add(secondSubCategory.Value);
|
|
}
|
|
|
|
break;
|
|
case ItemType.Jewelry:
|
|
category = BazaarCategoryFilterType.Accessories;
|
|
subCategories.Add(EquipmentTypeToSubCategory3(itemDto.EquipmentSlot));
|
|
break;
|
|
case ItemType.Specialist:
|
|
category = BazaarCategoryFilterType.Specialist;
|
|
subCategories.Add(SpMorphToSubCategory(itemDto));
|
|
break;
|
|
case ItemType.Box:
|
|
var usableItemSubType = (UsableItemSubType)itemDto.ItemSubType;
|
|
switch (usableItemSubType)
|
|
{
|
|
case UsableItemSubType.PetBead:
|
|
category = BazaarCategoryFilterType.Pet;
|
|
registerForAllSubcategories = true;
|
|
break;
|
|
case UsableItemSubType.PartnerBead:
|
|
category = BazaarCategoryFilterType.Partner;
|
|
registerForAllSubcategories = true;
|
|
break;
|
|
case UsableItemSubType.PartnerSpHolder:
|
|
category = BazaarCategoryFilterType.Partner;
|
|
registerForAllSubcategories = true;
|
|
break;
|
|
case UsableItemSubType.SpecialistHolder:
|
|
category = BazaarCategoryFilterType.Specialist;
|
|
registerForAllSubcategories = true;
|
|
break;
|
|
case UsableItemSubType.FairyBead:
|
|
category = BazaarCategoryFilterType.Accessories;
|
|
subCategories.Add((byte)BazaarCategoryAccessoriesSubFilterType.Fairy);
|
|
break;
|
|
case UsableItemSubType.VehicleBead:
|
|
category = BazaarCategoryFilterType.StoreMount;
|
|
registerForAllSubcategories = true;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
case ItemType.Shell:
|
|
category = BazaarCategoryFilterType.Shell;
|
|
var shellItemSubType = (ShellItemSubType)itemDto.ItemSubType;
|
|
subCategories.Add(shellItemSubType switch
|
|
{
|
|
ShellItemSubType.Weapon => (byte)BazaarCategoryShellSubFilterType.Weapon,
|
|
ShellItemSubType.Armor => (byte)BazaarCategoryShellSubFilterType.Clothing,
|
|
_ => default
|
|
});
|
|
break;
|
|
case ItemType.Main:
|
|
category = BazaarCategoryFilterType.MainItem;
|
|
subCategories.Add((byte)BazaarCategoryMainItemSubFilterType.GeneralItems);
|
|
break;
|
|
case ItemType.Upgrade:
|
|
category = BazaarCategoryFilterType.MainItem;
|
|
subCategories.Add((byte)BazaarCategoryMainItemSubFilterType.Material);
|
|
break;
|
|
case ItemType.Production:
|
|
category = BazaarCategoryFilterType.MainItem;
|
|
subCategories.Add((byte)BazaarCategoryMainItemSubFilterType.ProductionItem);
|
|
break;
|
|
case ItemType.Special:
|
|
category = BazaarCategoryFilterType.MainItem;
|
|
subCategories.Add((byte)BazaarCategoryMainItemSubFilterType.SpecialItems);
|
|
break;
|
|
case ItemType.Potion:
|
|
category = BazaarCategoryFilterType.MainItem;
|
|
subCategories.Add((byte)BazaarCategoryMainItemSubFilterType.HealingPotion);
|
|
break;
|
|
case ItemType.Event:
|
|
category = BazaarCategoryFilterType.MainItem;
|
|
subCategories.Add((byte)BazaarCategoryMainItemSubFilterType.Event);
|
|
break;
|
|
case ItemType.Title:
|
|
category = BazaarCategoryFilterType.MainItem;
|
|
subCategories.Add((byte)BazaarCategoryMainItemSubFilterType.Title);
|
|
break;
|
|
case ItemType.Sell:
|
|
category = BazaarCategoryFilterType.ConsumerItem;
|
|
subCategories.Add((byte)BazaarCategoryConsumerItemSubFilterType.SaleItem);
|
|
break;
|
|
case ItemType.Food:
|
|
category = BazaarCategoryFilterType.ConsumerItem;
|
|
subCategories.Add((byte)BazaarCategoryConsumerItemSubFilterType.Food);
|
|
break;
|
|
case ItemType.Snack:
|
|
category = BazaarCategoryFilterType.ConsumerItem;
|
|
subCategories.Add((byte)BazaarCategoryConsumerItemSubFilterType.Snack);
|
|
break;
|
|
case ItemType.Magical:
|
|
category = BazaarCategoryFilterType.ConsumerItem;
|
|
subCategories.Add((byte)BazaarCategoryConsumerItemSubFilterType.MagicItem);
|
|
break;
|
|
case ItemType.Material:
|
|
category = BazaarCategoryFilterType.ConsumerItem;
|
|
subCategories.Add((byte)BazaarCategoryConsumerItemSubFilterType.Ingredients);
|
|
break;
|
|
case ItemType.PetPartnerItem:
|
|
category = BazaarCategoryFilterType.ConsumerItem;
|
|
subCategories.Add((byte)BazaarCategoryConsumerItemSubFilterType.PartnerItem);
|
|
break;
|
|
}
|
|
|
|
return (category, subCategories, registerForAllSubcategories);
|
|
}
|
|
|
|
private static byte ItemTypeClassToSubCategory(byte itemTypeClass)
|
|
{
|
|
return itemTypeClass switch
|
|
{
|
|
(int)ItemClassType.Adventurer => (byte)BazaarCategoryWeaponArmourSubFilterType.Adventurer,
|
|
(int)ItemClassType.Swordsman => (byte)BazaarCategoryWeaponArmourSubFilterType.Swordsman,
|
|
(int)ItemClassType.Archer => (byte)BazaarCategoryWeaponArmourSubFilterType.Archer,
|
|
(int)ItemClassType.Mage => (byte)BazaarCategoryWeaponArmourSubFilterType.Magician,
|
|
(int)ItemClassType.MartialArtist => (byte)BazaarCategoryWeaponArmourSubFilterType.MartialArtist,
|
|
_ => default
|
|
};
|
|
}
|
|
|
|
private static byte EquipmentTypeToSubCategory1(EquipmentType equipmentType)
|
|
{
|
|
return equipmentType switch
|
|
{
|
|
EquipmentType.Hat => (byte)BazaarCategoryEquipmentSubFilterType.Hat,
|
|
EquipmentType.Mask => (byte)BazaarCategoryEquipmentSubFilterType.Accessory,
|
|
EquipmentType.Gloves => (byte)BazaarCategoryEquipmentSubFilterType.Gloves,
|
|
EquipmentType.Boots => (byte)BazaarCategoryEquipmentSubFilterType.Shoes,
|
|
EquipmentType.CostumeSuit => (byte)BazaarCategoryEquipmentSubFilterType.Costume,
|
|
EquipmentType.CostumeHat => (byte)BazaarCategoryEquipmentSubFilterType.CostumeHat,
|
|
EquipmentType.WeaponSkin => (byte)BazaarCategoryEquipmentSubFilterType.CostumeWeapon,
|
|
EquipmentType.Wings => (byte)BazaarCategoryEquipmentSubFilterType.CostumeWings,
|
|
_ => default
|
|
};
|
|
}
|
|
|
|
private static byte? EquipmentTypeToSubCategory2(EquipmentType equipmentType, GenderType genderType)
|
|
{
|
|
if (genderType == GenderType.Unisex)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
bool isMale = genderType == GenderType.Male;
|
|
|
|
return equipmentType switch
|
|
{
|
|
EquipmentType.CostumeSuit => (byte)(isMale ? BazaarCategoryEquipmentSubFilterType.CostumeMale : BazaarCategoryEquipmentSubFilterType.CostumeFemale),
|
|
EquipmentType.CostumeHat => (byte)(isMale ? BazaarCategoryEquipmentSubFilterType.CostumeHatMale : BazaarCategoryEquipmentSubFilterType.CostumeHatFemale),
|
|
_ => null
|
|
};
|
|
}
|
|
|
|
private static byte EquipmentTypeToSubCategory3(EquipmentType equipmentType)
|
|
{
|
|
return equipmentType switch
|
|
{
|
|
EquipmentType.Necklace => (byte)BazaarCategoryAccessoriesSubFilterType.Necklace,
|
|
EquipmentType.Ring => (byte)BazaarCategoryAccessoriesSubFilterType.Ring,
|
|
EquipmentType.Bracelet => (byte)BazaarCategoryAccessoriesSubFilterType.Bracelet,
|
|
EquipmentType.Fairy => (byte)BazaarCategoryAccessoriesSubFilterType.Fairy,
|
|
EquipmentType.Amulet => (byte)BazaarCategoryAccessoriesSubFilterType.Amulet,
|
|
_ => default
|
|
};
|
|
}
|
|
|
|
private static byte SpMorphToSubCategory(ItemDTO item)
|
|
{
|
|
int morphId = Convert.ToInt32(item.Morph);
|
|
if (!Enum.IsDefined(typeof(MorphIdType), morphId))
|
|
{
|
|
return default;
|
|
}
|
|
|
|
var morph = (MorphIdType)morphId;
|
|
return morph switch
|
|
{
|
|
MorphIdType.Pyjama => (byte)BazaarCategorySpecialistSubFilterType.Pyjama,
|
|
MorphIdType.Warrior => (byte)BazaarCategorySpecialistSubFilterType.Warrior,
|
|
MorphIdType.Ninja => (byte)BazaarCategorySpecialistSubFilterType.Ninja,
|
|
MorphIdType.Ranger => (byte)BazaarCategorySpecialistSubFilterType.Ranger,
|
|
MorphIdType.Assassin => (byte)BazaarCategorySpecialistSubFilterType.Assassin,
|
|
MorphIdType.RedMagician => (byte)BazaarCategorySpecialistSubFilterType.RedMagician,
|
|
MorphIdType.HolyMage => (byte)BazaarCategorySpecialistSubFilterType.HolyMage,
|
|
MorphIdType.Chicken => (byte)BazaarCategorySpecialistSubFilterType.ChickenCostume,
|
|
MorphIdType.Jajamaru => (byte)BazaarCategorySpecialistSubFilterType.Jajamaru,
|
|
MorphIdType.Crusader => (byte)BazaarCategorySpecialistSubFilterType.Crusader,
|
|
MorphIdType.Berserker => (byte)BazaarCategorySpecialistSubFilterType.Berserker,
|
|
MorphIdType.Destroyer => (byte)BazaarCategorySpecialistSubFilterType.Destroyer,
|
|
MorphIdType.WildKeeper => (byte)BazaarCategorySpecialistSubFilterType.WildKeeper,
|
|
MorphIdType.BlueMagician => (byte)BazaarCategorySpecialistSubFilterType.BlueMagician,
|
|
MorphIdType.DarkGunner => (byte)BazaarCategorySpecialistSubFilterType.DarkGunner,
|
|
MorphIdType.Pirate => (byte)BazaarCategorySpecialistSubFilterType.Pirate,
|
|
MorphIdType.Gladiator => (byte)BazaarCategorySpecialistSubFilterType.Gladiator,
|
|
MorphIdType.FireCannoneer => (byte)BazaarCategorySpecialistSubFilterType.FireCannoneer,
|
|
MorphIdType.Volcano => (byte)BazaarCategorySpecialistSubFilterType.Volcano,
|
|
MorphIdType.BattleMonk => (byte)BazaarCategorySpecialistSubFilterType.BattleMonk,
|
|
MorphIdType.Scout => (byte)BazaarCategorySpecialistSubFilterType.Scout,
|
|
MorphIdType.TideLord => (byte)BazaarCategorySpecialistSubFilterType.TideLord,
|
|
MorphIdType.DeathReaper => (byte)BazaarCategorySpecialistSubFilterType.DeathReaper,
|
|
MorphIdType.DemonHunter => (byte)BazaarCategorySpecialistSubFilterType.DemonHunter,
|
|
MorphIdType.Seer => (byte)BazaarCategorySpecialistSubFilterType.Seer,
|
|
MorphIdType.Renegade => (byte)BazaarCategorySpecialistSubFilterType.Renegade,
|
|
MorphIdType.AvengingAngel => (byte)BazaarCategorySpecialistSubFilterType.AvengingAngel,
|
|
MorphIdType.Archmage => (byte)BazaarCategorySpecialistSubFilterType.Archmage,
|
|
MorphIdType.DraconicFist => (byte)BazaarCategorySpecialistSubFilterType.DraconicFist,
|
|
MorphIdType.MysticArts => (byte)BazaarCategorySpecialistSubFilterType.MysticArts,
|
|
MorphIdType.WeddingCostume => (byte)BazaarCategorySpecialistSubFilterType.WeddingCostume,
|
|
MorphIdType.MasterWolf => (byte)BazaarCategorySpecialistSubFilterType.MasterWolf,
|
|
MorphIdType.DemonWarrior => (byte)BazaarCategorySpecialistSubFilterType.DemonWarrior,
|
|
_ => default
|
|
};
|
|
}
|
|
|
|
private BazaarLevelFilterType GetItemLevelFilterByInstance(ItemInstanceDTO itemInstanceDto, ItemInstanceType instanceType)
|
|
{
|
|
switch (instanceType)
|
|
{
|
|
case ItemInstanceType.BoxInstance:
|
|
case ItemInstanceType.SpecialistInstance:
|
|
ItemInstanceDTO specialistInstanceDto = itemInstanceDto;
|
|
return GetItemLevelFilterByLevel(specialistInstanceDto.SpLevel, false);
|
|
default:
|
|
(ItemDTO itemDto, BazaarLevelFilterType bazaarLevelFilterType) = _cachedItems.Get(itemInstanceDto.ItemVNum);
|
|
return itemDto.ItemType == ItemType.Shell
|
|
? GetItemLevelFilterByLevel(itemInstanceDto.Upgrade, false)
|
|
: bazaarLevelFilterType;
|
|
}
|
|
}
|
|
|
|
private static BazaarLevelFilterType GetItemLevelFilterByLevel(byte level, bool isHeroic)
|
|
{
|
|
if (isHeroic)
|
|
{
|
|
if (level is < 1 or > 60)
|
|
{
|
|
return BazaarLevelFilterType.ChampionGear;
|
|
}
|
|
|
|
return (BazaarLevelFilterType)(Convert.ToByte(Math.Ceiling(level / 10f)) + (byte)BazaarLevelFilterType.ChampionGear);
|
|
}
|
|
|
|
if (level is < 1 or > 99)
|
|
{
|
|
return BazaarLevelFilterType.All;
|
|
}
|
|
|
|
return (BazaarLevelFilterType)Convert.ToByte(Math.Ceiling(level / 10f));
|
|
}
|
|
|
|
private static bool ItemLevelFilterChecker(BazaarLevelFilterType demandedFilterType, BazaarLevelFilterType itemFilterType)
|
|
{
|
|
return demandedFilterType == itemFilterType || demandedFilterType == BazaarLevelFilterType.All || demandedFilterType == BazaarLevelFilterType.ChampionGear && itemFilterType switch
|
|
{
|
|
BazaarLevelFilterType.ChampionLevelOneToTen => true,
|
|
BazaarLevelFilterType.ChampionLevelElevenToTwenty => true,
|
|
BazaarLevelFilterType.ChampionLevelTwentyOneToThirty => true,
|
|
BazaarLevelFilterType.ChampionLevelThirtyOneToForty => true,
|
|
BazaarLevelFilterType.ChampionLevelFortyOneToFifty => true,
|
|
BazaarLevelFilterType.ChampionLevelFiftyOneToSixty => true,
|
|
_ => false
|
|
};
|
|
}
|
|
|
|
private static BazaarUpgradeFilterType GetUpgradeFilterByInstance(ItemInstanceDTO itemInstanceDto)
|
|
{
|
|
if (15 < itemInstanceDto.Upgrade)
|
|
{
|
|
return BazaarUpgradeFilterType.All;
|
|
}
|
|
|
|
return (BazaarUpgradeFilterType)(itemInstanceDto.Upgrade + 1);
|
|
}
|
|
|
|
private static BazaarRarityFilterType GetRarityFilterByInstance(ItemInstanceDTO itemInstanceDto)
|
|
{
|
|
if (itemInstanceDto.Rarity is < 0 or > 8)
|
|
{
|
|
return BazaarRarityFilterType.All;
|
|
}
|
|
|
|
return (BazaarRarityFilterType)(itemInstanceDto.Rarity + 1);
|
|
}
|
|
|
|
private static BazaarPerfectionFilterType GetPerfectionFilterByInstance(ItemInstanceDTO itemInstanceDto)
|
|
{
|
|
const int max = 100;
|
|
return itemInstanceDto.SpStoneUpgrade switch
|
|
{
|
|
< 1 or < max => BazaarPerfectionFilterType.All,
|
|
max => BazaarPerfectionFilterType.NintyOneToHundred,
|
|
_ => (BazaarPerfectionFilterType)Convert.ToByte(Math.Ceiling(itemInstanceDto.SpStoneUpgrade / 10f))
|
|
};
|
|
}
|
|
|
|
private static BazaarCategoryPartnerSubFilterType GetPartnerSubCategoryOfAttack(ItemDTO item)
|
|
{
|
|
return item.PartnerClass switch
|
|
{
|
|
(byte)AttackType.Melee => BazaarCategoryPartnerSubFilterType.CloseAttack,
|
|
(byte)AttackType.Ranged => BazaarCategoryPartnerSubFilterType.RemoteAttack,
|
|
(byte)AttackType.Magical => BazaarCategoryPartnerSubFilterType.Magic,
|
|
_ => BazaarCategoryPartnerSubFilterType.All
|
|
};
|
|
}
|
|
|
|
private IReadOnlyCollection<int> GetItemVNumsByCategoryAndSubCategory(BazaarCategoryFilterType categoryFilterType, byte subTypeFilter)
|
|
{
|
|
if (categoryFilterType == BazaarCategoryFilterType.All || !_itemVnumByCategoryAndSubCategory.ContainsKey(categoryFilterType) ||
|
|
!_itemVnumByCategoryAndSubCategory[categoryFilterType].ContainsKey(subTypeFilter))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return _itemVnumByCategoryAndSubCategory[categoryFilterType][subTypeFilter];
|
|
}
|
|
}
|
|
} |