add delta rate

This commit is contained in:
DismissedLight
2024-06-18 00:07:31 +08:00
parent 9ae45a4cc4
commit a3ab24554a
27 changed files with 201 additions and 105 deletions

View File

@@ -9,6 +9,7 @@ using Snap.Hutao.Model.Primitive;
using Snap.Hutao.Service.Metadata;
using Snap.Hutao.ViewModel.Complex;
using Snap.Hutao.Web.Hutao.SpiralAbyss;
using System.Runtime.CompilerServices;
namespace Snap.Hutao.Service.Hutao;
@@ -124,6 +125,32 @@ internal sealed partial class HutaoSpiralAbyssStatisticsCache : IHutaoSpiralAbys
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static IEnumerable<TResult> CurrentLeftJoinLast<TElement, TKey, TResult>(IEnumerable<TElement> current, IEnumerable<TElement>? last, Func<TElement, TKey> keySelector, Func<TElement, TElement?, TResult> resultSelector)
where TKey : notnull
{
if (last is null)
{
foreach (TElement element in current)
{
yield return resultSelector(element, default);
}
}
else
{
Dictionary<TKey, TElement> lastMap = [];
foreach (TElement element in last)
{
lastMap[keySelector(element)] = element;
}
foreach (TElement element in current)
{
yield return resultSelector(element, lastMap.GetValueOrDefault(keySelector(element)));
}
}
}
private async ValueTask<Dictionary<AvatarId, Avatar>> GetIdAvatarMapExtendedAsync()
{
if (idAvatarExtendedMap is null)
@@ -137,86 +164,91 @@ internal sealed partial class HutaoSpiralAbyssStatisticsCache : IHutaoSpiralAbys
private async ValueTask AvatarCollocationsAsync(Dictionary<AvatarId, Avatar> idAvatarMap, Dictionary<WeaponId, Weapon> idWeaponMap, Dictionary<ExtendedEquipAffixId, Model.Metadata.Reliquary.ReliquarySet> idReliquarySetMap)
{
List<AvatarCollocation> avatarCollocationsRaw;
List<AvatarCollocation> raw, rawLast;
using (IServiceScope scope = serviceProvider.CreateScope())
{
IHutaoSpiralAbyssService hutaoService = scope.ServiceProvider.GetRequiredService<IHutaoSpiralAbyssService>();
avatarCollocationsRaw = await hutaoService.GetAvatarCollocationsAsync().ConfigureAwait(false);
raw = await hutaoService.GetAvatarCollocationsAsync(false).ConfigureAwait(false);
rawLast = await hutaoService.GetAvatarCollocationsAsync(true).ConfigureAwait(false);
}
AvatarCollocations = avatarCollocationsRaw.SelectList(co => new AvatarCollocationView()
AvatarCollocations = CurrentLeftJoinLast(raw, rawLast, data => data.AvatarId, (raw, rawLast) => new AvatarCollocationView()
{
AvatarId = co.AvatarId,
Avatars = co.Avatars.SelectList(a => new AvatarView(idAvatarMap[a.Item], a.Rate)),
Weapons = co.Weapons.SelectList(w => new WeaponView(idWeaponMap[w.Item], w.Rate)),
ReliquarySets = co.Reliquaries.SelectList(r => new ReliquarySetView(r, idReliquarySetMap)),
AvatarId = raw.AvatarId,
Avatars = CurrentLeftJoinLast(raw.Avatars, rawLast?.Avatars, data => data.Item, (avatar, avatarLast) => new AvatarView(idAvatarMap[avatar.Item], avatar.Rate, avatarLast?.Rate)).ToList(),
Weapons = CurrentLeftJoinLast(raw.Weapons, rawLast?.Weapons, data => data.Item, (weapon, weaponLast) => new WeaponView(idWeaponMap[weapon.Item], weapon.Rate, weaponLast?.Rate)).ToList(),
ReliquarySets = CurrentLeftJoinLast(raw.Reliquaries, rawLast?.Reliquaries, data => data.Item, (relic, relicLast) => new ReliquarySetView(idReliquarySetMap, relic, relicLast)).ToList(),
}).ToDictionary(a => a.AvatarId);
}
private async ValueTask WeaponCollocationsAsync(Dictionary<AvatarId, Avatar> idAvatarMap)
{
List<WeaponCollocation> weaponCollocationsRaw;
List<WeaponCollocation> raw, rawLast;
using (IServiceScope scope = serviceProvider.CreateScope())
{
IHutaoSpiralAbyssService hutaoService = scope.ServiceProvider.GetRequiredService<IHutaoSpiralAbyssService>();
weaponCollocationsRaw = await hutaoService.GetWeaponCollocationsAsync().ConfigureAwait(false);
raw = await hutaoService.GetWeaponCollocationsAsync(false).ConfigureAwait(false);
rawLast = await hutaoService.GetWeaponCollocationsAsync(true).ConfigureAwait(false);
}
WeaponCollocations = weaponCollocationsRaw.SelectList(co => new WeaponCollocationView()
WeaponCollocations = CurrentLeftJoinLast(raw, rawLast, data => data.WeaponId, (raw, rawLast) => new WeaponCollocationView()
{
WeaponId = co.WeaponId,
Avatars = co.Avatars.SelectList(a => new AvatarView(idAvatarMap[a.Item], a.Rate)),
WeaponId = raw.WeaponId,
Avatars = CurrentLeftJoinLast(raw.Avatars, rawLast?.Avatars, data => data.Item, (avatar, avatarLast) => new AvatarView(idAvatarMap[avatar.Item], avatar.Rate, avatarLast?.Rate)).ToList(),
}).ToDictionary(w => w.WeaponId);
}
[SuppressMessage("", "SH003")]
private async Task AvatarAppearanceRankAsync(Dictionary<AvatarId, Avatar> idAvatarMap)
{
List<AvatarAppearanceRank> avatarAppearanceRanksRaw;
List<AvatarAppearanceRank> raw, rawLast;
using (IServiceScope scope = serviceProvider.CreateScope())
{
IHutaoSpiralAbyssService hutaoService = scope.ServiceProvider.GetRequiredService<IHutaoSpiralAbyssService>();
avatarAppearanceRanksRaw = await hutaoService.GetAvatarAppearanceRanksAsync().ConfigureAwait(false);
raw = await hutaoService.GetAvatarAppearanceRanksAsync(false).ConfigureAwait(false);
rawLast = await hutaoService.GetAvatarAppearanceRanksAsync(true).ConfigureAwait(false);
}
AvatarAppearanceRanks = avatarAppearanceRanksRaw.SortByDescending(r => r.Floor).SelectList(rank => new AvatarRankView
AvatarAppearanceRanks = CurrentLeftJoinLast(raw.SortByDescending(r => r.Floor), rawLast, data => data.Floor, (raw, rawLast) => new AvatarRankView
{
Floor = SH.FormatModelBindingHutaoComplexRankFloor(rank.Floor),
Avatars = rank.Ranks.SortByDescending(r => r.Rate).SelectList(rank => new AvatarView(idAvatarMap[rank.Item], rank.Rate)),
});
Floor = SH.FormatModelBindingHutaoComplexRankFloor(raw.Floor),
Avatars = CurrentLeftJoinLast(raw.Ranks, rawLast?.Ranks, data => data.Item, (rank, rankLast) => new AvatarView(idAvatarMap[rank.Item], rank.Rate, rankLast?.Rate)).OrderByDescending(r => r.Rate).ToList(),
}).ToList();
}
[SuppressMessage("", "SH003")]
private async Task AvatarUsageRanksAsync(Dictionary<AvatarId, Avatar> idAvatarMap)
{
List<AvatarUsageRank> avatarUsageRanksRaw;
List<AvatarUsageRank> raw, rawLast;
using (IServiceScope scope = serviceProvider.CreateScope())
{
IHutaoSpiralAbyssService hutaoService = scope.ServiceProvider.GetRequiredService<IHutaoSpiralAbyssService>();
avatarUsageRanksRaw = await hutaoService.GetAvatarUsageRanksAsync().ConfigureAwait(false);
raw = await hutaoService.GetAvatarUsageRanksAsync(false).ConfigureAwait(false);
rawLast = await hutaoService.GetAvatarUsageRanksAsync(true).ConfigureAwait(false);
}
AvatarUsageRanks = avatarUsageRanksRaw.SortByDescending(r => r.Floor).SelectList(rank => new AvatarRankView
AvatarUsageRanks = CurrentLeftJoinLast(raw.SortByDescending(r => r.Floor), rawLast, data => data.Floor, (raw, rawLast) => new AvatarRankView
{
Floor = SH.FormatModelBindingHutaoComplexRankFloor(rank.Floor),
Avatars = rank.Ranks.SortByDescending(r => r.Rate).SelectList(rank => new AvatarView(idAvatarMap[rank.Item], rank.Rate)),
});
Floor = SH.FormatModelBindingHutaoComplexRankFloor(raw.Floor),
Avatars = CurrentLeftJoinLast(raw.Ranks, rawLast?.Ranks, data => data.Item, (rank, rankLast) => new AvatarView(idAvatarMap[rank.Item], rank.Rate, rankLast?.Rate)).OrderByDescending(r => r.Rate).ToList(),
}).ToList();
}
[SuppressMessage("", "SH003")]
private async Task AvatarConstellationInfosAsync(Dictionary<AvatarId, Avatar> idAvatarMap)
{
List<AvatarConstellationInfo> avatarConstellationInfosRaw;
List<AvatarConstellationInfo> raw, rawLast;
using (IServiceScope scope = serviceProvider.CreateScope())
{
IHutaoSpiralAbyssService hutaoService = scope.ServiceProvider.GetRequiredService<IHutaoSpiralAbyssService>();
avatarConstellationInfosRaw = await hutaoService.GetAvatarConstellationInfosAsync().ConfigureAwait(false);
raw = await hutaoService.GetAvatarConstellationInfosAsync(false).ConfigureAwait(false);
rawLast = await hutaoService.GetAvatarConstellationInfosAsync(true).ConfigureAwait(false);
}
AvatarConstellationInfos = avatarConstellationInfosRaw.SortBy(i => i.HoldingRate).SelectList(info =>
AvatarConstellationInfos = CurrentLeftJoinLast(raw.SortBy(i => i.HoldingRate), rawLast, data => data.AvatarId, (raw, rawLast) => new AvatarConstellationInfoView(idAvatarMap[raw.AvatarId], raw.HoldingRate, rawLast?.HoldingRate)
{
return new AvatarConstellationInfoView(idAvatarMap[info.AvatarId], info.HoldingRate, info.Constellations.SelectList(x => x.Rate));
});
Rates = CurrentLeftJoinLast(raw.Constellations, rawLast?.Constellations, data => data.Item, (rate, rataLast) => new RateAndDelta(rate.Rate, rataLast?.Rate)).ToList(),
}).ToList();
}
[SuppressMessage("", "SH003")]

View File

@@ -7,5 +7,5 @@ namespace Snap.Hutao.Service.Metadata.ContextAbstraction;
internal interface IMetadataDictionaryIdAchievementSource
{
public Dictionary<AchievementId, Model.Metadata.Achievement.Achievement> IdAchievementMap { get; set; }
Dictionary<AchievementId, Model.Metadata.Achievement.Achievement> IdAchievementMap { get; set; }
}

View File

@@ -7,5 +7,5 @@ namespace Snap.Hutao.Service.Metadata.ContextAbstraction;
internal interface IMetadataDictionaryIdAvatarSource
{
public Dictionary<AvatarId, Model.Metadata.Avatar.Avatar> IdAvatarMap { get; set; }
Dictionary<AvatarId, Model.Metadata.Avatar.Avatar> IdAvatarMap { get; set; }
}

View File

@@ -8,5 +8,5 @@ namespace Snap.Hutao.Service.Metadata.ContextAbstraction;
internal interface IMetadataDictionaryIdMaterialSource
{
public Dictionary<MaterialId, Material> IdMaterialMap { get; set; }
Dictionary<MaterialId, Material> IdMaterialMap { get; set; }
}

View File

@@ -8,5 +8,5 @@ namespace Snap.Hutao.Service.Metadata.ContextAbstraction;
internal interface IMetadataDictionaryIdReliquaryAffixWeightSource
{
public Dictionary<AvatarId, ReliquaryAffixWeight> IdReliquaryAffixWeightMap { get; set; }
Dictionary<AvatarId, ReliquaryAffixWeight> IdReliquaryAffixWeightMap { get; set; }
}

View File

@@ -8,5 +8,5 @@ namespace Snap.Hutao.Service.Metadata.ContextAbstraction;
internal interface IMetadataDictionaryIdReliquaryMainPropertySource
{
public Dictionary<ReliquaryMainAffixId, FightProperty> IdReliquaryMainPropertyMap { get; set; }
Dictionary<ReliquaryMainAffixId, FightProperty> IdReliquaryMainPropertyMap { get; set; }
}

View File

@@ -8,5 +8,5 @@ namespace Snap.Hutao.Service.Metadata.ContextAbstraction;
internal interface IMetadataDictionaryIdReliquarySource
{
public Dictionary<ReliquaryId, Reliquary> IdReliquaryMap { get; set; }
Dictionary<ReliquaryId, Reliquary> IdReliquaryMap { get; set; }
}

View File

@@ -8,5 +8,5 @@ namespace Snap.Hutao.Service.Metadata.ContextAbstraction;
internal interface IMetadataDictionaryIdReliquarySubAffixSource
{
public Dictionary<ReliquarySubAffixId, ReliquarySubAffix> IdReliquarySubAffixMap { get; set; }
Dictionary<ReliquarySubAffixId, ReliquarySubAffix> IdReliquarySubAffixMap { get; set; }
}

View File

@@ -7,5 +7,5 @@ namespace Snap.Hutao.Service.Metadata.ContextAbstraction;
internal interface IMetadataDictionaryIdWeaponSource
{
public Dictionary<WeaponId, Model.Metadata.Weapon.Weapon> IdWeaponMap { get; set; }
Dictionary<WeaponId, Model.Metadata.Weapon.Weapon> IdWeaponMap { get; set; }
}

View File

@@ -5,5 +5,5 @@ namespace Snap.Hutao.Service.Metadata.ContextAbstraction;
internal interface IMetadataDictionaryNameAvatarSource
{
public Dictionary<string, Model.Metadata.Avatar.Avatar> NameAvatarMap { get; set; }
Dictionary<string, Model.Metadata.Avatar.Avatar> NameAvatarMap { get; set; }
}

View File

@@ -5,5 +5,5 @@ namespace Snap.Hutao.Service.Metadata.ContextAbstraction;
internal interface IMetadataDictionaryNameWeaponSource
{
public Dictionary<string, Model.Metadata.Weapon.Weapon> NameWeaponMap { get; set; }
Dictionary<string, Model.Metadata.Weapon.Weapon> NameWeaponMap { get; set; }
}

View File

@@ -5,5 +5,5 @@ namespace Snap.Hutao.Service.Metadata.ContextAbstraction;
internal interface IMetadataListAchievementSource
{
public List<Model.Metadata.Achievement.Achievement> Achievements { get; set; }
List<Model.Metadata.Achievement.Achievement> Achievements { get; set; }
}

View File

@@ -7,5 +7,5 @@ namespace Snap.Hutao.Service.Metadata.ContextAbstraction;
internal interface IMetadataListChapterSource
{
public List<Chapter> Chapters { get; set; }
List<Chapter> Chapters { get; set; }
}

View File

@@ -7,5 +7,5 @@ namespace Snap.Hutao.Service.Metadata.ContextAbstraction;
internal interface IMetadataListGachaEventSource
{
public List<GachaEvent> GachaEvents { get; set; }
List<GachaEvent> GachaEvents { get; set; }
}

View File

@@ -7,5 +7,5 @@ namespace Snap.Hutao.Service.Metadata.ContextAbstraction;
internal interface IMetadataListMaterialSource
{
public List<Material> Materials { get; set; }
List<Material> Materials { get; set; }
}

View File

@@ -7,5 +7,5 @@ namespace Snap.Hutao.Service.Metadata.ContextAbstraction;
internal interface IMetadataListProfilePictureSource
{
public List<ProfilePicture> ProfilePictures { get; set; }
List<ProfilePicture> ProfilePictures { get; set; }
}

View File

@@ -7,5 +7,5 @@ namespace Snap.Hutao.Service.Metadata.ContextAbstraction;
internal interface IMetadataListReliquaryMainAffixLevelSource
{
public List<ReliquaryMainAffixLevel> ReliquaryMainAffixLevels { get; set; }
List<ReliquaryMainAffixLevel> ReliquaryMainAffixLevels { get; set; }
}

View File

@@ -7,5 +7,5 @@ namespace Snap.Hutao.Service.Metadata.ContextAbstraction;
internal interface IMetadataListReliquarySource
{
public List<Reliquary> Reliquaries { get; set; }
List<Reliquary> Reliquaries { get; set; }
}

View File

@@ -12,20 +12,10 @@ namespace Snap.Hutao.Model.Binding.Hutao;
[HighQuality]
internal sealed class AvatarConstellationInfoView : AvatarView
{
/// <summary>
/// 构造一个新的角色命座信息
/// </summary>
/// <param name="avatar">角色</param>
/// <param name="rate">持有率</param>
/// <param name="rates">命座比率</param>
public AvatarConstellationInfoView(Avatar avatar, double rate, List<double> rates)
: base(avatar, rate)
public AvatarConstellationInfoView(Avatar avatar, double rate, double? lastRate)
: base(avatar, rate, lastRate)
{
Rates = rates.SelectList(r => $"{r:P3}");
}
/// <summary>
/// 命座比率
/// </summary>
public List<string> Rates { get; }
}
public List<RateAndDelta> Rates { get; set; } = default!;
}

View File

@@ -2,6 +2,7 @@
// Licensed under the MIT license.
using Snap.Hutao.Model;
using Snap.Hutao.Model.Binding.Hutao;
using Snap.Hutao.Model.Intrinsic;
using Snap.Hutao.Model.Metadata.Avatar;
using Snap.Hutao.Model.Metadata.Converter;
@@ -12,20 +13,15 @@ namespace Snap.Hutao.ViewModel.Complex;
/// 角色
/// </summary>
[HighQuality]
internal class AvatarView : INameIconSide
internal class AvatarView : RateAndDelta, INameIconSide
{
/// <summary>
/// 构造一个胡桃数据库角色
/// </summary>
/// <param name="avatar">元数据角色</param>
/// <param name="rate">率</param>
public AvatarView(Avatar avatar, double rate = 0)
public AvatarView(Avatar avatar, double rate, double? lastRate = default)
: base(rate, lastRate)
{
Name = avatar.Name;
Icon = AvatarIconConverter.IconNameToUri(avatar.Icon);
SideIcon = AvatarSideIconConverter.IconNameToUri(avatar.SideIcon);
Quality = avatar.Quality;
Rate = $"{rate:P3}";
}
/// <summary>
@@ -47,9 +43,4 @@ internal class AvatarView : INameIconSide
/// 星级
/// </summary>
public QualityType Quality { get; }
/// <summary>
/// 比率
/// </summary>
public string Rate { get; }
}

View File

@@ -0,0 +1,45 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Model.Binding.Hutao;
internal class RateAndDelta
{
public RateAndDelta(double rate, double? lastRate)
{
Rate = $"{rate:P3}";
if (lastRate.HasValue)
{
RateDelta = FormatDelta(rate - lastRate.Value);
}
else
{
RateDelta = string.Empty;
}
}
public string Rate { get; }
public string RateDelta { get; }
public static RateAndDelta Create((double Rate, double? LastRate) tuple)
{
return new RateAndDelta(tuple.Rate, tuple.LastRate);
}
public static RateAndDelta Create((double Rate, double LastRate) tuple)
{
return new RateAndDelta(tuple.Rate, tuple.LastRate);
}
private static string FormatDelta(double value)
{
return value switch
{
>= 0 => $"+{value:P3}",
< 0 => $"{value:P3}",
_ => string.Empty,
};
}
}

View File

@@ -1,6 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Model.Binding.Hutao;
using Snap.Hutao.Model.Metadata.Converter;
using Snap.Hutao.Model.Primitive;
using Snap.Hutao.Web.Hutao.SpiralAbyss;
@@ -12,16 +13,12 @@ namespace Snap.Hutao.ViewModel.Complex;
/// <summary>
/// 圣遗物套装
/// </summary>
internal sealed class ReliquarySetView
internal sealed class ReliquarySetView : RateAndDelta
{
/// <summary>
/// 构造一个新的胡桃数据库圣遗物套装
/// </summary>
/// <param name="reliquarySetRate">圣遗物套装率</param>
/// <param name="idReliquarySetMap">圣遗物套装映射</param>
public ReliquarySetView(ItemRate<ReliquarySets, double> reliquarySetRate, Dictionary<ExtendedEquipAffixId, Model.Metadata.Reliquary.ReliquarySet> idReliquarySetMap)
public ReliquarySetView(Dictionary<ExtendedEquipAffixId, Model.Metadata.Reliquary.ReliquarySet> idReliquarySetMap, ItemRate<ReliquarySets, double> setRate, ItemRate<ReliquarySets, double>? lastSetRate)
: base(setRate.Rate, lastSetRate?.Rate)
{
ReliquarySets sets = reliquarySetRate.Item;
ReliquarySets sets = setRate.Item;
if (!sets.IsNullOrEmpty())
{
@@ -41,8 +38,6 @@ internal sealed class ReliquarySetView
{
Name = SH.ViewModelComplexReliquarySetViewEmptyName;
}
Rate = $"{reliquarySetRate.Rate:P3}";
}
/// <summary>
@@ -54,9 +49,4 @@ internal sealed class ReliquarySetView
/// 图标
/// </summary>
public List<Uri>? Icons { get; }
/// <summary>
/// 比率
/// </summary>
public string Rate { get; }
}

View File

@@ -21,7 +21,7 @@ internal sealed class Team : List<AvatarView>
foreach (StringSegment item in new StringTokenizer(team.Item, [',']))
{
uint id = uint.Parse(item.AsSpan(), CultureInfo.InvariantCulture);
Add(new(idAvatarMap[id]));
Add(new(idAvatarMap[id], 0));
}
AddRange(new AvatarView[4 - Count]);
@@ -33,6 +33,7 @@ internal sealed class Team : List<AvatarView>
/// <summary>
/// 上场次数
/// </summary>
[Obsolete("Name this with another name")]
public string Rate { get; }
public int Rank { get; set; }

View File

@@ -2,6 +2,7 @@
// Licensed under the MIT license.
using Snap.Hutao.Model;
using Snap.Hutao.Model.Binding.Hutao;
using Snap.Hutao.Model.Intrinsic;
using Snap.Hutao.Model.Metadata.Converter;
using Snap.Hutao.Model.Metadata.Weapon;
@@ -12,19 +13,14 @@ namespace Snap.Hutao.ViewModel.Complex;
/// 胡桃数据库武器
/// </summary>
[HighQuality]
internal sealed class WeaponView : INameIcon
internal sealed class WeaponView : RateAndDelta, INameIcon
{
/// <summary>
/// 构造一个胡桃数据库武器
/// </summary>
/// <param name="weapon">元数据武器</param>
/// <param name="rate">率</param>
public WeaponView(Weapon weapon, double rate)
public WeaponView(Weapon weapon, double rate, double? lastRate)
: base(rate, lastRate)
{
Name = weapon.Name;
Icon = EquipIconConverter.IconNameToUri(weapon.Icon);
Quality = weapon.Quality;
Rate = $"{rate:P3}";
}
/// <summary>
@@ -41,9 +37,4 @@ internal sealed class WeaponView : INameIcon
/// 星级
/// </summary>
public QualityType Quality { get; }
/// <summary>
/// 比率
/// </summary>
public string Rate { get; }
}

View File

@@ -16,6 +16,7 @@ internal sealed class AvatarConstellationInfo : AvatarBuild
/// <summary>
/// 命之座
/// Order is guaranteed as ascending
/// </summary>
public List<ItemRate<int, double>> Constellations { get; set; } = default!;
}

View File

@@ -10,7 +10,7 @@ namespace Snap.Hutao.Web.Hutao.SpiralAbyss;
/// 圣遗物套装
/// </summary>
[HighQuality]
internal sealed class ReliquarySet
internal sealed class ReliquarySet : IEquatable<ReliquarySet>
{
/// <summary>
/// 构造一个新的圣遗物套装
@@ -34,7 +34,31 @@ internal sealed class ReliquarySet
/// </summary>
public int Count { get; }
/// <inheritdoc/>
public bool Equals(ReliquarySet? other)
{
if (other is null)
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return EquipAffixId == other.EquipAffixId && Count == other.Count;
}
public override bool Equals(object? obj)
{
return Equals(obj as ReliquarySet);
}
public override int GetHashCode()
{
return HashCode.Combine(EquipAffixId, Count);
}
public override string ToString()
{
return $"{EquipAffixId.Value}-{Count}";

View File

@@ -10,7 +10,7 @@ namespace Snap.Hutao.Web.Hutao.SpiralAbyss;
/// </summary>
[HighQuality]
[JsonConverter(typeof(ReliquarySetsConverter))]
internal sealed class ReliquarySets : List<ReliquarySet>
internal sealed class ReliquarySets : List<ReliquarySet>, IEquatable<ReliquarySets>
{
/// <summary>
/// 构造一个新的圣遗物包装器
@@ -20,4 +20,35 @@ internal sealed class ReliquarySets : List<ReliquarySet>
: base(sets)
{
}
public bool Equals(ReliquarySets? other)
{
if (other is null)
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return this.SequenceEqual(other);
}
public override bool Equals(object? obj)
{
return Equals(obj as ReliquarySets);
}
public override int GetHashCode()
{
HashCode hashCode = default;
foreach (ReliquarySet set in this)
{
hashCode.Add(set);
}
return hashCode.ToHashCode();
}
}