From 6a42c36a76deec5503b72721ab41129c628dea0c Mon Sep 17 00:00:00 2001 From: Lightczx <1686188646@qq.com> Date: Thu, 25 Apr 2024 14:44:06 +0800 Subject: [PATCH] optimization --- .../AvatarInfo/AvatarInfoDbBulkOperation.cs | 131 +++++++----------- .../Service/AvatarInfo/AvatarInfoService.cs | 2 +- .../Factory/Builder/AvatarViewBuilder.cs | 6 +- .../Builder/AvatarViewBuilderExtension.cs | 60 +++----- .../Builder/EquipViewBuilderExtension.cs | 33 +++++ .../Factory/Builder/IAvatarViewBuilder.cs | 5 +- .../Factory/Builder/IEquipViewBuilder.cs | 11 ++ .../Builder/INameIconDescriptionBuilder.cs | 13 ++ .../Factory/Builder/IReliquaryViewBuilder.cs | 10 ++ .../Factory/Builder/IScoreAccess.cs | 9 ++ .../Factory/Builder/IWeaponViewBuilder.cs | 5 +- .../NameIconDescriptionBuilderExtension.cs | 33 +++++ .../Factory/Builder/ReliquaryViewBuilder.cs | 13 ++ .../Builder/ReliquaryViewBuilderExtension.cs | 66 +++++++++ .../Factory/Builder/ScoreAccessExtension.cs | 16 +++ .../Factory/Builder/WeaponViewBuilder.cs | 4 +- .../Builder/WeaponViewBuilderExtension.cs | 29 ++-- .../Factory/SummaryAvatarFactory.cs | 6 +- .../AvatarInfo/Factory/SummaryHelper.cs | 3 - .../Factory/SummaryReliquaryFactory.cs | 114 +++++++-------- ...culateAvatarDetailAvatarInfoTransformer.cs | 2 +- ...ameRecordCharacterAvatarInfoTransformer.cs | 2 +- .../Transformer/IAvatarInfoTransformer.cs | 2 +- .../Snap.Hutao/View/Control/SkillPivot.xaml | 4 +- .../Snap.Hutao/View/Guide/GuideView.xaml | 2 +- .../View/Page/AvatarPropertyPage.xaml | 4 +- .../ViewModel/AvatarProperty/AvatarView.cs | 9 +- 27 files changed, 374 insertions(+), 220 deletions(-) create mode 100644 src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/EquipViewBuilderExtension.cs create mode 100644 src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/IEquipViewBuilder.cs create mode 100644 src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/INameIconDescriptionBuilder.cs create mode 100644 src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/IReliquaryViewBuilder.cs create mode 100644 src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/IScoreAccess.cs create mode 100644 src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/NameIconDescriptionBuilderExtension.cs create mode 100644 src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/ReliquaryViewBuilder.cs create mode 100644 src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/ReliquaryViewBuilderExtension.cs create mode 100644 src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/ScoreAccessExtension.cs diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoDbBulkOperation.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoDbBulkOperation.cs index 50750d87..626a2d3c 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoDbBulkOperation.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoDbBulkOperation.cs @@ -12,7 +12,9 @@ using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate; using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord; using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Avatar; using Snap.Hutao.Web.Response; +using System.Reflection.Emit; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using CalculateAvatar = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.Avatar; using EnkaAvatarInfo = Snap.Hutao.Web.Enka.Model.AvatarInfo; using EntityAvatarInfo = Snap.Hutao.Model.Entity.AvatarInfo; @@ -21,9 +23,6 @@ using RecordPlayerInfo = Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.PlayerInfo; namespace Snap.Hutao.Service.AvatarInfo; -/// -/// 角色信息数据库操作 -/// [HighQuality] [ConstructorGenerated] [Injection(InjectAs.Singleton)] @@ -32,18 +31,10 @@ internal sealed partial class AvatarInfoDbBulkOperation private readonly IServiceProvider serviceProvider; private readonly IAvatarInfoDbService avatarInfoDbService; - /// - /// 更新数据库角色信息 - /// - /// uid - /// Enka信息 - /// 取消令牌 - /// 角色列表 - public List UpdateDbAvatarInfosByShowcase(string uid, IEnumerable webInfos, CancellationToken token) + public async ValueTask> UpdateDbAvatarInfosByShowcaseAsync(string uid, IEnumerable webInfos, CancellationToken token) { - token.ThrowIfCancellationRequested(); - List dbInfos = avatarInfoDbService.GetAvatarInfoListByUid(uid); - EnsureItemsAvatarIdDistinct(ref dbInfos, uid); + List dbInfos = await avatarInfoDbService.GetAvatarInfoListByUidAsync(uid).ConfigureAwait(false); + EnsureItemsAvatarIdUnique(ref dbInfos, uid, out Dictionary dbInfoMap); using (IServiceScope scope = serviceProvider.CreateScope()) { @@ -56,28 +47,19 @@ internal sealed partial class AvatarInfoDbBulkOperation continue; } - token.ThrowIfCancellationRequested(); - EntityAvatarInfo? entity = dbInfos.SingleOrDefault(i => i.Info.AvatarId == webInfo.AvatarId); + EntityAvatarInfo? entity = dbInfoMap.GetValueOrDefault(webInfo.AvatarId); AddOrUpdateAvatarInfo(entity, uid, appDbContext, webInfo); } - token.ThrowIfCancellationRequested(); - return avatarInfoDbService.GetAvatarInfoListByUid(uid); + return await avatarInfoDbService.GetAvatarInfoListByUidAsync(uid).ConfigureAwait(false); } } - /// - /// 米游社我的角色方式 更新数据库角色信息 - /// - /// 用户与角色 - /// 取消令牌 - /// 角色列表 public async ValueTask> UpdateDbAvatarInfosByGameRecordCharacterAsync(UserAndUid userAndUid, CancellationToken token) { - token.ThrowIfCancellationRequested(); string uid = userAndUid.Uid.Value; List dbInfos = await avatarInfoDbService.GetAvatarInfoListByUidAsync(uid).ConfigureAwait(false); - EnsureItemsAvatarIdDistinct(ref dbInfos, uid); + EnsureItemsAvatarIdUnique(ref dbInfos, uid, out Dictionary dbInfoMap); using (IServiceScope scope = serviceProvider.CreateScope()) { @@ -90,51 +72,47 @@ internal sealed partial class AvatarInfoDbBulkOperation .GetPlayerInfoAsync(userAndUid, token) .ConfigureAwait(false); - if (playerInfoResponse.IsOk()) + if (!playerInfoResponse.IsOk()) { - Response charactersResponse = await gameRecordClient - .GetCharactersAsync(userAndUid, playerInfoResponse.Data, token) - .ConfigureAwait(false); + goto Return; + } - token.ThrowIfCancellationRequested(); + Response charactersResponse = await gameRecordClient + .GetCharactersAsync(userAndUid, playerInfoResponse.Data, token) + .ConfigureAwait(false); - if (charactersResponse.IsOk()) + if (!charactersResponse.IsOk()) + { + goto Return; + } + + List characters = charactersResponse.Data.Avatars; + + GameRecordCharacterAvatarInfoTransformer transformer = serviceProvider + .GetRequiredService(); + + foreach (RecordCharacter character in characters) + { + if (AvatarIds.IsPlayer(character.Id)) { - List characters = charactersResponse.Data.Avatars; - - GameRecordCharacterAvatarInfoTransformer transformer = serviceProvider - .GetRequiredService(); - - foreach (RecordCharacter character in characters) - { - if (AvatarIds.IsPlayer(character.Id)) - { - continue; - } - - token.ThrowIfCancellationRequested(); - EntityAvatarInfo? entity = dbInfos.SingleOrDefault(i => i.Info.AvatarId == character.Id); - AddOrUpdateAvatarInfo(entity, character.Id, uid, appDbContext, transformer, character); - } + continue; } + + EntityAvatarInfo? entity = dbInfoMap.GetValueOrDefault(character.Id); + AddOrUpdateAvatarInfo(entity, character.Id, uid, appDbContext, transformer, character); } } + Return: return await avatarInfoDbService.GetAvatarInfoListByUidAsync(uid).ConfigureAwait(false); } - /// - /// 米游社养成计算方式 更新数据库角色信息 - /// - /// 用户与角色 - /// 取消令牌 - /// 角色列表 public async ValueTask> UpdateDbAvatarInfosByCalculateAvatarDetailAsync(UserAndUid userAndUid, CancellationToken token) { token.ThrowIfCancellationRequested(); string uid = userAndUid.Uid.Value; List dbInfos = await avatarInfoDbService.GetAvatarInfoListByUidAsync(uid).ConfigureAwait(false); - EnsureItemsAvatarIdDistinct(ref dbInfos, uid); + EnsureItemsAvatarIdUnique(ref dbInfos, uid, out Dictionary dbInfoMap); using (IServiceScope scope = serviceProvider.CreateScope()) { @@ -155,8 +133,6 @@ internal sealed partial class AvatarInfoDbBulkOperation continue; } - token.ThrowIfCancellationRequested(); - Response detailAvatarResponse = await calculateClient .GetAvatarDetailAsync(userAndUid, avatar, token) .ConfigureAwait(false); @@ -166,8 +142,7 @@ internal sealed partial class AvatarInfoDbBulkOperation continue; } - token.ThrowIfCancellationRequested(); - EntityAvatarInfo? entity = dbInfos.SingleOrDefault(i => i.Info.AvatarId == avatar.Id); + EntityAvatarInfo? entity = dbInfoMap.GetValueOrDefault(avatar.Id); AddOrUpdateAvatarInfo(entity, avatar.Id, uid, appDbContext, transformer, detailAvatarResponse.Data); } } @@ -181,15 +156,14 @@ internal sealed partial class AvatarInfoDbBulkOperation if (entity is null) { entity = EntityAvatarInfo.From(uid, webInfo); - entity.ShowcaseRefreshTime = DateTimeOffset.UtcNow; - appDbContext.AvatarInfos.AddAndSave(entity); } else { entity.Info = webInfo; - entity.ShowcaseRefreshTime = DateTimeOffset.UtcNow; - appDbContext.AvatarInfos.UpdateAndSave(entity); } + + entity.ShowcaseRefreshTime = DateTimeOffset.UtcNow; + appDbContext.AvatarInfos.UpdateAndSave(entity); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -200,17 +174,16 @@ internal sealed partial class AvatarInfoDbBulkOperation EnkaAvatarInfo avatarInfo = new() { AvatarId = avatarId }; transformer.Transform(ref avatarInfo, source); entity = EntityAvatarInfo.From(uid, avatarInfo); - entity.CalculatorRefreshTime = DateTimeOffset.UtcNow; - appDbContext.AvatarInfos.AddAndSave(entity); } else { EnkaAvatarInfo avatarInfo = entity.Info; transformer.Transform(ref avatarInfo, source); entity.Info = avatarInfo; - entity.CalculatorRefreshTime = DateTimeOffset.UtcNow; - appDbContext.AvatarInfos.UpdateAndSave(entity); } + + entity.CalculatorRefreshTime = DateTimeOffset.UtcNow; + appDbContext.AvatarInfos.UpdateAndSave(entity); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -221,29 +194,29 @@ internal sealed partial class AvatarInfoDbBulkOperation EnkaAvatarInfo avatarInfo = new() { AvatarId = avatarId }; transformer.Transform(ref avatarInfo, source); entity = EntityAvatarInfo.From(uid, avatarInfo); - entity.GameRecordRefreshTime = DateTimeOffset.UtcNow; - appDbContext.AvatarInfos.AddAndSave(entity); } else { EnkaAvatarInfo avatarInfo = entity.Info; transformer.Transform(ref avatarInfo, source); entity.Info = avatarInfo; - entity.GameRecordRefreshTime = DateTimeOffset.UtcNow; - appDbContext.AvatarInfos.UpdateAndSave(entity); } + + entity.GameRecordRefreshTime = DateTimeOffset.UtcNow; + appDbContext.AvatarInfos.UpdateAndSave(entity); } - private void EnsureItemsAvatarIdDistinct(ref List dbInfos, string uid) + private void EnsureItemsAvatarIdUnique(ref List dbInfos, string uid, out Dictionary dbInfoMap) { - int distinctCount = dbInfos.Select(info => info.Info.AvatarId).ToHashSet().Count; - - // Avatars are actually less than the list told us. - // This means that there are duplicate items. - if (distinctCount < dbInfos.Count) + dbInfoMap = []; + foreach (ref readonly EntityAvatarInfo info in CollectionsMarshal.AsSpan(dbInfos)) { - avatarInfoDbService.RemoveAvatarInfoRangeByUid(uid); - dbInfos = []; + if (!dbInfoMap.TryAdd(info.Info.AvatarId, info)) + { + avatarInfoDbService.RemoveAvatarInfoRangeByUid(uid); + dbInfoMap.Clear(); + dbInfos.Clear(); + } } } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoService.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoService.cs index 44ed0d8b..1846f283 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoService.cs @@ -52,7 +52,7 @@ internal sealed partial class AvatarInfoService : IAvatarInfoService return new(RefreshResult.ShowcaseNotOpen, default); } - List list = avatarInfoDbBulkOperation.UpdateDbAvatarInfosByShowcase(userAndUid.Uid.Value, resp.AvatarInfoList, token); + List list = await avatarInfoDbBulkOperation.UpdateDbAvatarInfosByShowcaseAsync(userAndUid.Uid.Value, resp.AvatarInfoList, token); Summary summary = await GetSummaryCoreAsync(list, token).ConfigureAwait(false); return new(RefreshResult.Ok, summary); } diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/AvatarViewBuilder.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/AvatarViewBuilder.cs index bb9a2004..7b8e05cb 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/AvatarViewBuilder.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/AvatarViewBuilder.cs @@ -1,9 +1,13 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using Snap.Hutao.ViewModel.AvatarProperty; + namespace Snap.Hutao.Service.AvatarInfo.Factory.Builder; internal sealed class AvatarViewBuilder : IAvatarViewBuilder { - public ViewModel.AvatarProperty.AvatarView AvatarView { get; } = new(); + public AvatarView View { get; } = new(); + + public float Score { get => View.Score; set => View.Score = value; } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/AvatarViewBuilderExtension.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/AvatarViewBuilderExtension.cs index 30c5806d..12b2164a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/AvatarViewBuilderExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/AvatarViewBuilderExtension.cs @@ -20,13 +20,13 @@ internal static class AvatarViewBuilderExtension Costume costume = avatar.Costumes.Single(c => c.Id == id); // Set to costume icon - builder.AvatarView.Icon = AvatarIconConverter.IconNameToUri(costume.FrontIcon); - builder.AvatarView.SideIcon = AvatarIconConverter.IconNameToUri(costume.SideIcon); + builder.View.Icon = AvatarIconConverter.IconNameToUri(costume.FrontIcon); + builder.View.SideIcon = AvatarIconConverter.IconNameToUri(costume.SideIcon); } else { - builder.AvatarView.Icon = AvatarIconConverter.IconNameToUri(avatar.Icon); - builder.AvatarView.SideIcon = AvatarIconConverter.IconNameToUri(avatar.SideIcon); + builder.View.Icon = AvatarIconConverter.IconNameToUri(avatar.Icon); + builder.View.SideIcon = AvatarIconConverter.IconNameToUri(avatar.SideIcon); } return builder; @@ -41,7 +41,7 @@ internal static class AvatarViewBuilderExtension public static TBuilder SetCalculatorRefreshTimeFormat(this TBuilder builder, string calculatorRefreshTimeFormat) where TBuilder : IAvatarViewBuilder { - return builder.Configure(b => b.AvatarView.CalculatorRefreshTimeFormat = calculatorRefreshTimeFormat); + return builder.Configure(b => b.View.CalculatorRefreshTimeFormat = calculatorRefreshTimeFormat); } public static TBuilder SetConstellations(this TBuilder builder, List talents, List? talentIds) @@ -65,7 +65,7 @@ internal static class AvatarViewBuilderExtension public static TBuilder SetConstellations(this TBuilder builder, List constellations) where TBuilder : IAvatarViewBuilder { - return builder.Configure(b => b.AvatarView.Constellations = constellations); + return builder.Configure(b => b.View.Constellations = constellations); } public static TBuilder SetCritScore(this TBuilder builder, Dictionary? fightPropMap) @@ -90,19 +90,13 @@ internal static class AvatarViewBuilderExtension public static TBuilder SetCritScore(this TBuilder builder, float critScore) where TBuilder : IAvatarViewBuilder { - return builder.SetCritScore($"{critScore:F2}"); - } - - public static TBuilder SetCritScore(this TBuilder builder, string critScore) - where TBuilder : IAvatarViewBuilder - { - return builder.Configure(b => b.AvatarView.CritScore = critScore); + return builder.Configure(b => b.View.CritScore = critScore); } public static TBuilder SetElement(this TBuilder builder, ElementType element) where TBuilder : IAvatarViewBuilder { - return builder.Configure(b => b.AvatarView.Element = element); + return builder.Configure(b => b.View.Element = element); } public static TBuilder SetFetterLevel(this TBuilder builder, FetterLevel? level) @@ -110,7 +104,7 @@ internal static class AvatarViewBuilderExtension { if (level.TryGetValue(out FetterLevel value)) { - return builder.Configure(b => b.AvatarView.FetterLevel = value); + return builder.Configure(b => b.View.FetterLevel = value); } return builder; @@ -119,7 +113,7 @@ internal static class AvatarViewBuilderExtension public static TBuilder SetFetterLevel(this TBuilder builder, uint level) where TBuilder : IAvatarViewBuilder { - return builder.Configure(b => b.AvatarView.FetterLevel = level); + return builder.Configure(b => b.View.FetterLevel = level); } public static TBuilder SetGameRecordRefreshTimeFormat(this TBuilder builder, DateTimeOffset refreshTime, Func format, string defaultValue) @@ -131,13 +125,13 @@ internal static class AvatarViewBuilderExtension public static TBuilder SetGameRecordRefreshTimeFormat(this TBuilder builder, string gameRecordRefreshTimeFormat) where TBuilder : IAvatarViewBuilder { - return builder.Configure(b => b.AvatarView.GameRecordRefreshTimeFormat = gameRecordRefreshTimeFormat); + return builder.Configure(b => b.View.GameRecordRefreshTimeFormat = gameRecordRefreshTimeFormat); } public static TBuilder SetId(this TBuilder builder, AvatarId id) where TBuilder : IAvatarViewBuilder { - return builder.Configure(b => b.AvatarView.Id = id); + return builder.Configure(b => b.View.Id = id); } public static TBuilder SetLevelNumber(this TBuilder builder, uint? levelNumber) @@ -145,7 +139,7 @@ internal static class AvatarViewBuilderExtension { if (levelNumber.TryGetValue(out uint value)) { - return builder.Configure(b => b.AvatarView.LevelNumber = value); + return builder.Configure(b => b.View.LevelNumber = value); } return builder; @@ -154,43 +148,31 @@ internal static class AvatarViewBuilderExtension public static TBuilder SetName(this TBuilder builder, string name) where TBuilder : IAvatarViewBuilder { - return builder.Configure(b => b.AvatarView.Name = name); + return builder.Configure(b => b.View.Name = name); } public static TBuilder SetNameCard(this TBuilder builder, Uri nameCard) where TBuilder : IAvatarViewBuilder { - return builder.Configure(b => b.AvatarView.NameCard = nameCard); + return builder.Configure(b => b.View.NameCard = nameCard); } public static TBuilder SetProperties(this TBuilder builder, List properties) where TBuilder : IAvatarViewBuilder { - return builder.Configure(b => b.AvatarView.Properties = properties); + return builder.Configure(b => b.View.Properties = properties); } public static TBuilder SetQuality(this TBuilder builder, QualityType quality) where TBuilder : IAvatarViewBuilder { - return builder.Configure(b => b.AvatarView.Quality = quality); + return builder.Configure(b => b.View.Quality = quality); } public static TBuilder SetReliquaries(this TBuilder builder, List reliquaries) where TBuilder : IAvatarViewBuilder { - return builder.Configure(b => b.AvatarView.Reliquaries = reliquaries); - } - - public static TBuilder SetScore(this TBuilder builder, float score) - where TBuilder : IAvatarViewBuilder - { - return builder.SetScore($"{score:F2}"); - } - - public static TBuilder SetScore(this TBuilder builder, string score) - where TBuilder : IAvatarViewBuilder - { - return builder.Configure(b => b.AvatarView.Score = score); + return builder.Configure(b => b.View.Reliquaries = reliquaries); } public static TBuilder SetShowcaseRefreshTimeFormat(this TBuilder builder, DateTimeOffset refreshTime, Func format, string defaultValue) @@ -202,7 +184,7 @@ internal static class AvatarViewBuilderExtension public static TBuilder SetShowcaseRefreshTimeFormat(this TBuilder builder, string showcaseRefreshTimeFormat) where TBuilder : IAvatarViewBuilder { - return builder.Configure(b => b.AvatarView.ShowcaseRefreshTimeFormat = showcaseRefreshTimeFormat); + return builder.Configure(b => b.View.ShowcaseRefreshTimeFormat = showcaseRefreshTimeFormat); } public static TBuilder SetSkills(this TBuilder builder, Dictionary? skillLevelMap, Dictionary? proudSkillExtraLevelMap, List proudSkills) @@ -249,12 +231,12 @@ internal static class AvatarViewBuilderExtension public static TBuilder SetSkills(this TBuilder builder, List skills) where TBuilder : IAvatarViewBuilder { - return builder.Configure(b => b.AvatarView.Skills = skills); + return builder.Configure(b => b.View.Skills = skills); } public static TBuilder SetWeapon(this TBuilder builder, WeaponView? weapon) where TBuilder : IAvatarViewBuilder { - return builder.Configure(b => b.AvatarView.Weapon = weapon); + return builder.Configure(b => b.View.Weapon = weapon); } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/EquipViewBuilderExtension.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/EquipViewBuilderExtension.cs new file mode 100644 index 00000000..a9d11439 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/EquipViewBuilderExtension.cs @@ -0,0 +1,33 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.Core.Abstraction.Extension; +using Snap.Hutao.Model; +using Snap.Hutao.Model.Intrinsic; +using Snap.Hutao.ViewModel.AvatarProperty; + +namespace Snap.Hutao.Service.AvatarInfo.Factory.Builder; + +internal static class EquipViewBuilderExtension +{ + public static TBuilder SetLevel(this TBuilder builder, string level) + where TBuilder : IEquipViewBuilder + where T : EquipView + { + return builder.Configure(b => b.View.Level = level); + } + + public static TBuilder SetQuality(this TBuilder builder, QualityType quality) + where TBuilder : IEquipViewBuilder + where T : EquipView + { + return builder.Configure(b => b.View.Quality = quality); + } + + public static TBuilder SetMainProperty(this TBuilder builder, NameValue mainProperty) + where TBuilder : IEquipViewBuilder + where T : EquipView + { + return builder.Configure(b => b.View.MainProperty = mainProperty); + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/IAvatarViewBuilder.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/IAvatarViewBuilder.cs index f7c70c5b..47896e90 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/IAvatarViewBuilder.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/IAvatarViewBuilder.cs @@ -2,10 +2,11 @@ // Licensed under the MIT license. using Snap.Hutao.Core.Abstraction; +using Snap.Hutao.ViewModel.AvatarProperty; namespace Snap.Hutao.Service.AvatarInfo.Factory.Builder; -internal interface IAvatarViewBuilder : IBuilder +internal interface IAvatarViewBuilder : IBuilder, IScoreAccess { - ViewModel.AvatarProperty.AvatarView AvatarView { get; } + AvatarView View { get; } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/IEquipViewBuilder.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/IEquipViewBuilder.cs new file mode 100644 index 00000000..4e515832 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/IEquipViewBuilder.cs @@ -0,0 +1,11 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.ViewModel.AvatarProperty; + +namespace Snap.Hutao.Service.AvatarInfo.Factory.Builder; + +internal interface IEquipViewBuilder : INameIconDescriptionBuilder + where T : EquipView +{ +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/INameIconDescriptionBuilder.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/INameIconDescriptionBuilder.cs new file mode 100644 index 00000000..873522b3 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/INameIconDescriptionBuilder.cs @@ -0,0 +1,13 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.Core.Abstraction; +using Snap.Hutao.ViewModel.AvatarProperty; + +namespace Snap.Hutao.Service.AvatarInfo.Factory.Builder; + +internal interface INameIconDescriptionBuilder : IBuilder + where T : NameIconDescription +{ + T View { get; } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/IReliquaryViewBuilder.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/IReliquaryViewBuilder.cs new file mode 100644 index 00000000..5c189551 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/IReliquaryViewBuilder.cs @@ -0,0 +1,10 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.ViewModel.AvatarProperty; + +namespace Snap.Hutao.Service.AvatarInfo.Factory.Builder; + +internal interface IReliquaryViewBuilder : IEquipViewBuilder, IScoreAccess +{ +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/IScoreAccess.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/IScoreAccess.cs new file mode 100644 index 00000000..57bd4aa7 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/IScoreAccess.cs @@ -0,0 +1,9 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +namespace Snap.Hutao.Service.AvatarInfo.Factory.Builder; + +internal interface IScoreAccess +{ + float Score { get; set; } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/IWeaponViewBuilder.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/IWeaponViewBuilder.cs index d3eaf724..08dbf8e2 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/IWeaponViewBuilder.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/IWeaponViewBuilder.cs @@ -1,11 +1,10 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. -using Snap.Hutao.Core.Abstraction; +using Snap.Hutao.ViewModel.AvatarProperty; namespace Snap.Hutao.Service.AvatarInfo.Factory.Builder; -internal interface IWeaponViewBuilder : IBuilder +internal interface IWeaponViewBuilder : IEquipViewBuilder { - ViewModel.AvatarProperty.WeaponView WeaponView { get; } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/NameIconDescriptionBuilderExtension.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/NameIconDescriptionBuilderExtension.cs new file mode 100644 index 00000000..5f5474f9 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/NameIconDescriptionBuilderExtension.cs @@ -0,0 +1,33 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.Core.Abstraction.Extension; +using Snap.Hutao.Model; +using Snap.Hutao.Model.Intrinsic; +using Snap.Hutao.ViewModel.AvatarProperty; + +namespace Snap.Hutao.Service.AvatarInfo.Factory.Builder; + +internal static class NameIconDescriptionBuilderExtension +{ + public static TBuilder SetDescription(this TBuilder builder, string description) + where TBuilder : INameIconDescriptionBuilder + where T : NameIconDescription + { + return builder.Configure(b => b.View.Description = description); + } + + public static TBuilder SetIcon(this TBuilder builder, Uri icon) + where TBuilder : INameIconDescriptionBuilder + where T : NameIconDescription + { + return builder.Configure(b => b.View.Icon = icon); + } + + public static TBuilder SetName(this TBuilder builder, string name) + where TBuilder : INameIconDescriptionBuilder + where T : NameIconDescription + { + return builder.Configure(b => b.View.Name = name); + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/ReliquaryViewBuilder.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/ReliquaryViewBuilder.cs new file mode 100644 index 00000000..c108ce92 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/ReliquaryViewBuilder.cs @@ -0,0 +1,13 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.ViewModel.AvatarProperty; + +namespace Snap.Hutao.Service.AvatarInfo.Factory.Builder; + +internal sealed class ReliquaryViewBuilder : IReliquaryViewBuilder +{ + public ReliquaryView View { get; } = new(); + + public float Score { get => View.Score; set => View.Score = value; } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/ReliquaryViewBuilderExtension.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/ReliquaryViewBuilderExtension.cs new file mode 100644 index 00000000..b7bc1296 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/ReliquaryViewBuilderExtension.cs @@ -0,0 +1,66 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.Core.Abstraction.Extension; +using Snap.Hutao.Model; +using Snap.Hutao.Model.Intrinsic; +using Snap.Hutao.ViewModel.AvatarProperty; + +namespace Snap.Hutao.Service.AvatarInfo.Factory.Builder; + +internal static class ReliquaryViewBuilderExtension +{ + public static TBuilder SetComposedSubProperties(this TBuilder builder, List composedSubProperties) + where TBuilder : IReliquaryViewBuilder + { + return builder.Configure(b => b.View.ComposedSubProperties = composedSubProperties); + } + + public static TBuilder SetDescription(this TBuilder builder, string description) + where TBuilder : IReliquaryViewBuilder + { + return builder.SetDescription(description); + } + + public static TBuilder SetIcon(this TBuilder builder, Uri icon) + where TBuilder : IReliquaryViewBuilder + { + return builder.SetIcon(icon); + } + + public static TBuilder SetLevel(this TBuilder builder, string level) + where TBuilder : IReliquaryViewBuilder + { + return builder.SetLevel(level); + } + + public static TBuilder SetMainProperty(this TBuilder builder, NameValue mainProperty) + where TBuilder : IReliquaryViewBuilder + { + return builder.SetMainProperty(mainProperty); + } + + public static TBuilder SetName(this TBuilder builder, string name) + where TBuilder : IReliquaryViewBuilder + { + return builder.SetName(name); + } + + public static TBuilder SetPrimarySubProperties(this TBuilder builder, List primarySubProperties) + where TBuilder : IReliquaryViewBuilder + { + return builder.Configure(b => b.View.PrimarySubProperties = primarySubProperties); + } + + public static TBuilder SetQuality(this TBuilder builder, QualityType quality) + where TBuilder : IReliquaryViewBuilder + { + return builder.SetQuality(quality); + } + + public static TBuilder SetSecondarySubProperties(this TBuilder builder, List secondarySubProperties) + where TBuilder : IReliquaryViewBuilder + { + return builder.Configure(b => b.View.SecondarySubProperties = secondarySubProperties); + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/ScoreAccessExtension.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/ScoreAccessExtension.cs new file mode 100644 index 00000000..c889c2ee --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/ScoreAccessExtension.cs @@ -0,0 +1,16 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.Core.Abstraction; +using Snap.Hutao.Core.Abstraction.Extension; + +namespace Snap.Hutao.Service.AvatarInfo.Factory.Builder; + +internal static class ScoreAccessExtension +{ + public static TBuilder SetScore(this TBuilder builder, float score) + where TBuilder : IBuilder, IScoreAccess + { + return builder.Configure(b => b.Score = score); + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/WeaponViewBuilder.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/WeaponViewBuilder.cs index b1e099e6..a9907fec 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/WeaponViewBuilder.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/WeaponViewBuilder.cs @@ -1,9 +1,11 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using Snap.Hutao.ViewModel.AvatarProperty; + namespace Snap.Hutao.Service.AvatarInfo.Factory.Builder; internal sealed class WeaponViewBuilder : IWeaponViewBuilder { - public ViewModel.AvatarProperty.WeaponView WeaponView { get; } = new(); + public WeaponView View { get; } = new(); } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/WeaponViewBuilderExtension.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/WeaponViewBuilderExtension.cs index 152829f8..61b16311 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/WeaponViewBuilderExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/Builder/WeaponViewBuilderExtension.cs @@ -6,6 +6,7 @@ using Snap.Hutao.Model; using Snap.Hutao.Model.Intrinsic; using Snap.Hutao.Model.Metadata.Converter; using Snap.Hutao.Model.Primitive; +using Snap.Hutao.ViewModel.AvatarProperty; using Snap.Hutao.Web.Enka.Model; namespace Snap.Hutao.Service.AvatarInfo.Factory.Builder; @@ -15,49 +16,49 @@ internal static class WeaponViewBuilderExtension public static TBuilder SetAffixLevelNumber(this TBuilder builder, uint affixLevelNumber) where TBuilder : IWeaponViewBuilder { - return builder.Configure(b => b.WeaponView.AffixLevelNumber = affixLevelNumber); + return builder.Configure(b => b.View.AffixLevelNumber = affixLevelNumber); } public static TBuilder SetAffixDescription(this TBuilder builder, string? affixDescription) where TBuilder : IWeaponViewBuilder { - return builder.Configure(b => b.WeaponView.AffixDescription = affixDescription ?? string.Empty); + return builder.Configure(b => b.View.AffixDescription = affixDescription ?? string.Empty); } - public static TBuilder SetAffixName(this TBuilder builder, string affixName) + public static TBuilder SetAffixName(this TBuilder builder, string? affixName) where TBuilder : IWeaponViewBuilder { - return builder.Configure(b => b.WeaponView.AffixName = affixName); + return builder.Configure(b => b.View.AffixName = affixName ?? string.Empty); } public static TBuilder SetDescription(this TBuilder builder, string description) where TBuilder : IWeaponViewBuilder { - return builder.Configure(b => b.WeaponView.Description = description); + return builder.SetDescription(description); } public static TBuilder SetIcon(this TBuilder builder, Uri icon) where TBuilder : IWeaponViewBuilder { - return builder.Configure(b => b.WeaponView.Icon = icon); + return builder.SetIcon(icon); } public static TBuilder SetId(this TBuilder builder, WeaponId id) where TBuilder : IWeaponViewBuilder { - return builder.Configure(b => b.WeaponView.Id = id); + return builder.Configure(b => b.View.Id = id); } public static TBuilder SetLevel(this TBuilder builder, string level) where TBuilder : IWeaponViewBuilder { - return builder.Configure(b => b.WeaponView.Level = level); + return builder.SetLevel(level); } public static TBuilder SetLevelNumber(this TBuilder builder, uint levelNumber) where TBuilder : IWeaponViewBuilder { - return builder.Configure(b => b.WeaponView.LevelNumber = levelNumber); + return builder.Configure(b => b.View.LevelNumber = levelNumber); } public static TBuilder SetMainProperty(this TBuilder builder, WeaponStat? mainStat) @@ -69,30 +70,30 @@ internal static class WeaponViewBuilderExtension public static TBuilder SetMainProperty(this TBuilder builder, NameValue mainProperty) where TBuilder : IWeaponViewBuilder { - return builder.Configure(b => b.WeaponView.MainProperty = mainProperty); + return builder.SetMainProperty(mainProperty); } public static TBuilder SetName(this TBuilder builder, string name) where TBuilder : IWeaponViewBuilder { - return builder.Configure(b => b.WeaponView.Name = name); + return builder.SetName(name); } public static TBuilder SetQuality(this TBuilder builder, QualityType quality) where TBuilder : IWeaponViewBuilder { - return builder.Configure(b => b.WeaponView.Quality = quality); + return builder.SetQuality(quality); } public static TBuilder SetSubProperty(this TBuilder builder, NameDescription subProperty) where TBuilder : IWeaponViewBuilder { - return builder.Configure(b => b.WeaponView.SubProperty = subProperty); + return builder.Configure(b => b.View.SubProperty = subProperty); } public static TBuilder SetWeaponType(this TBuilder builder, WeaponType weaponType) where TBuilder : IWeaponViewBuilder { - return builder.Configure(b => b.WeaponView.WeaponType = weaponType); + return builder.Configure(b => b.View.WeaponType = weaponType); } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryAvatarFactory.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryAvatarFactory.cs index e67cce99..426a941f 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryAvatarFactory.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryAvatarFactory.cs @@ -64,7 +64,7 @@ internal sealed class SummaryAvatarFactory .SetGameRecordRefreshTimeFormat(gameRecordRefreshTime, SH.FormatServiceAvatarInfoSummaryGameRecordRefreshTimeFormat, SH.ServiceAvatarInfoSummaryGameRecordNotRefreshed) .SetCalculatorRefreshTimeFormat(calculatorRefreshTime, SH.FormatServiceAvatarInfoSummaryCalculatorRefreshTimeFormat, SH.ServiceAvatarInfoSummaryCalculatorNotRefreshed) .SetCostumeIconOrDefault(avatarInfo, avatar) - .AvatarView; + .View; return propertyAvatar; } @@ -127,10 +127,10 @@ internal sealed class SummaryAvatarFactory .SetLevelNumber(equip.Weapon.Level) .SetSubProperty(subProperty) .SetAffixLevelNumber(affixLevel + 1) - .SetAffixName(weapon.Affix?.Name ?? string.Empty) + .SetAffixName(weapon.Affix?.Name) .SetAffixDescription(weapon.Affix?.Descriptions.Single(a => a.Level == affixLevel).Description) .SetWeaponType(weapon.WeaponType) - .WeaponView; + .View; } private readonly struct ReliquaryAndWeapon diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryHelper.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryHelper.cs index 98e5eeca..c1edbcc0 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryHelper.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryHelper.cs @@ -6,9 +6,6 @@ using Snap.Hutao.Model.Primitive; namespace Snap.Hutao.Service.AvatarInfo.Factory; -/// -/// 简述帮助类 -/// [HighQuality] internal static class SummaryHelper { diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryReliquaryFactory.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryReliquaryFactory.cs index 3998abd5..5e28614c 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryReliquaryFactory.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryReliquaryFactory.cs @@ -6,6 +6,7 @@ using Snap.Hutao.Model.Intrinsic; using Snap.Hutao.Model.Metadata.Converter; using Snap.Hutao.Model.Metadata.Reliquary; using Snap.Hutao.Model.Primitive; +using Snap.Hutao.Service.AvatarInfo.Factory.Builder; using Snap.Hutao.ViewModel.AvatarProperty; using System.Runtime.InteropServices; using MetadataReliquary = Snap.Hutao.Model.Metadata.Reliquary.Reliquary; @@ -37,38 +38,33 @@ internal sealed class SummaryReliquaryFactory MetadataReliquary reliquary = metadataContext.IdReliquaryMap[equip.ItemId]; ArgumentNullException.ThrowIfNull(equip.Reliquary); - List subProperty = equip.Reliquary.AppendPropIdList.EmptyIfNull().SelectList(CreateSubProperty); + List subProperties = equip.Reliquary.AppendPropIdList.EmptyIfNull().SelectList(CreateSubProperty); + + ReliquaryViewBuilder reliquaryViewBuilder = new ReliquaryViewBuilder() + .SetName(reliquary.Name) + .SetIcon(RelicIconConverter.IconNameToUri(reliquary.Icon)) + .SetDescription(reliquary.Description) + .SetLevel($"+{equip.Reliquary.Level - 1U}") + .SetQuality(reliquary.RankLevel); int affixCount = GetSecondaryAffixCount(reliquary, equip.Reliquary); - ReliquaryView result = new() + if (subProperties.Count > 0) { - // NameIconDescription - Name = reliquary.Name, - Icon = RelicIconConverter.IconNameToUri(reliquary.Icon), - Description = reliquary.Description, - - // EquipBase - Level = $"+{equip.Reliquary.Level - 1U}", - Quality = reliquary.RankLevel, - }; - - if (subProperty.Count > 0) - { - result.PrimarySubProperties = subProperty.GetRange(..^affixCount); - result.SecondarySubProperties = subProperty.GetRange(^affixCount..); - - ArgumentNullException.ThrowIfNull(equip.Flat.ReliquarySubstats); - result.ComposedSubProperties = CreateComposedSubProperties(equip.Reliquary.AppendPropIdList); + reliquaryViewBuilder + .SetPrimarySubProperties(subProperties.GetRange(..^affixCount)) + .SetSecondarySubProperties(subProperties.GetRange(^affixCount..)) + .SetComposedSubProperties(CreateComposedSubProperties(equip.Reliquary.AppendPropIdList)); ReliquaryMainAffixLevel relicLevel = metadataContext.ReliquaryMainAffixLevels.Single(r => r.Level == equip.Reliquary.Level && r.Rank == reliquary.RankLevel); FightProperty property = metadataContext.IdReliquaryMainPropertyMap[equip.Reliquary.MainPropId]; - result.MainProperty = FightPropertyFormat.ToNameValue(property, relicLevel.PropertyMap[property]); - result.Score = ScoreReliquary(property, reliquary, relicLevel, subProperty); + reliquaryViewBuilder + .SetMainProperty(FightPropertyFormat.ToNameValue(property, relicLevel.PropertyMap[property])) + .SetScore(ScoreReliquary(property, reliquary, relicLevel, subProperties)); } - return result; + return reliquaryViewBuilder.View; } private static int GetSecondaryAffixCount(MetadataReliquary metaReliquary, Web.Enka.Model.Reliquary enkaReliquary) @@ -115,18 +111,8 @@ internal sealed class SummaryReliquaryFactory info.Value += subAffix.Value; } - if (infos.Count > 4) - { - ThrowHelper.InvalidOperation("无效的圣遗物数据"); - } - - List results = []; - foreach (ref readonly SummaryReliquarySubPropertyCompositionInfo info in CollectionsMarshal.AsSpan(infos)) - { - results.Add(info.ToReliquaryComposedSubProperty()); - } - - return results; + HutaoException.ThrowIf(infos.Count > 4, "无效的圣遗物数据"); + return infos.SelectList(info => info.ToReliquaryComposedSubProperty()); } private float ScoreReliquary(FightProperty property, MetadataReliquary reliquary, ReliquaryMainAffixLevel relicLevel, List subProperties) @@ -162,42 +148,42 @@ internal sealed class SummaryReliquaryFactory FightProperty property = affix.Type; return new(property, FightPropertyFormat.FormatValue(property, affix.Value), ScoreSubAffix(appendPropId)); - } - private float ScoreSubAffix(in ReliquarySubAffixId appendId) - { - ReliquarySubAffix affix = metadataContext.IdReliquarySubAffixMap[appendId]; - - ReliquaryAffixWeight affixWeight = metadataContext.IdReliquaryAffixWeightMap.GetValueOrDefault(avatarInfo.AvatarId, ReliquaryAffixWeight.Default); - float weight = affixWeight[affix.Type] / 100F; - - // 数字词条,转换到等效百分比计算 - if (affix.Type is FightProperty.FIGHT_PROP_HP or FightProperty.FIGHT_PROP_ATTACK or FightProperty.FIGHT_PROP_DEFENSE) + float ScoreSubAffix(in ReliquarySubAffixId appendId) { - // 等效百分比 [ 当前小字词条 / 角色基本属性 ] - float equalPercent = affix.Value / avatarInfo.FightPropMap[affix.Type - 1]; + ReliquarySubAffix affix = metadataContext.IdReliquarySubAffixMap[appendId]; - // 获取对应百分比词条权重 - weight = affixWeight[affix.Type + 1] / 100F; + ReliquaryAffixWeight affixWeight = metadataContext.IdReliquaryAffixWeightMap.GetValueOrDefault(avatarInfo.AvatarId, ReliquaryAffixWeight.Default); + float weight = affixWeight[affix.Type] / 100F; - // 最大同属性百分比Id - // 第四五位是战斗属性位 - // 小字的加成词条在十位加一后即变换为百分比词条 - ReliquarySubAffixId maxPercentAffixId = SummaryHelper.GetAffixMaxId(appendId + 10U); + // 数字词条,转换到等效百分比计算 + if (affix.Type is FightProperty.FIGHT_PROP_HP or FightProperty.FIGHT_PROP_ATTACK or FightProperty.FIGHT_PROP_DEFENSE) + { + // 等效百分比 [ 当前小字词条 / 角色基本属性 ] + float equalPercent = affix.Value / avatarInfo.FightPropMap[affix.Type - 1]; - // 最大同属性百分比数值 - ReliquarySubAffix maxPercentAffix = metadataContext.IdReliquarySubAffixMap[maxPercentAffixId]; - Must.Argument( - maxPercentAffix.Type - is FightProperty.FIGHT_PROP_HP_PERCENT - or FightProperty.FIGHT_PROP_ATTACK_PERCENT - or FightProperty.FIGHT_PROP_DEFENSE_PERCENT, - "ReliquarySubAffix transform failed"); - float equalScore = equalPercent / maxPercentAffix.Value; + // 获取对应百分比词条权重 + weight = affixWeight[affix.Type + 1] / 100F; - return weight * equalScore * 100; + // 最大同属性百分比Id + // 第四五位是战斗属性位 + // 小字的加成词条在十位加一后即变换为百分比词条 + ReliquarySubAffixId maxPercentAffixId = SummaryHelper.GetAffixMaxId(appendId + 10U); + + // 最大同属性百分比数值 + ReliquarySubAffix maxPercentAffix = metadataContext.IdReliquarySubAffixMap[maxPercentAffixId]; + HutaoException.ThrowIfNot( + maxPercentAffix.Type + is FightProperty.FIGHT_PROP_HP_PERCENT + or FightProperty.FIGHT_PROP_ATTACK_PERCENT + or FightProperty.FIGHT_PROP_DEFENSE_PERCENT, + "ReliquarySubAffix transform failed"); + float equalScore = equalPercent / maxPercentAffix.Value; + + return weight * equalScore * 100; + } + + return weight * SummaryHelper.GetPercentSubAffixScore(appendId); } - - return weight * SummaryHelper.GetPercentSubAffixScore(appendId); } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Transformer/CalculateAvatarDetailAvatarInfoTransformer.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Transformer/CalculateAvatarDetailAvatarInfoTransformer.cs index 493c7fc8..916a72ba 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Transformer/CalculateAvatarDetailAvatarInfoTransformer.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Transformer/CalculateAvatarDetailAvatarInfoTransformer.cs @@ -14,7 +14,7 @@ namespace Snap.Hutao.Service.AvatarInfo.Transformer; internal sealed class CalculateAvatarDetailAvatarInfoTransformer : IAvatarInfoTransformer { /// - public void Transform(ref Web.Enka.Model.AvatarInfo avatarInfo, AvatarDetail source) + public void Transform(ref readonly Web.Enka.Model.AvatarInfo avatarInfo, AvatarDetail source) { // update skills avatarInfo.SkillLevelMap = source.SkillList.ToDictionary(s => (SkillId)s.Id, s => (SkillLevel)s.LevelCurrent); diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Transformer/GameRecordCharacterAvatarInfoTransformer.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Transformer/GameRecordCharacterAvatarInfoTransformer.cs index 141e0ae4..b99eab5f 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Transformer/GameRecordCharacterAvatarInfoTransformer.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Transformer/GameRecordCharacterAvatarInfoTransformer.cs @@ -15,7 +15,7 @@ namespace Snap.Hutao.Service.AvatarInfo.Transformer; internal sealed class GameRecordCharacterAvatarInfoTransformer : IAvatarInfoTransformer { /// - public void Transform(ref Web.Enka.Model.AvatarInfo avatarInfo, Character source) + public void Transform(ref readonly Web.Enka.Model.AvatarInfo avatarInfo, Character source) { // update fetter avatarInfo.FetterInfo ??= new(); diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Transformer/IAvatarInfoTransformer.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Transformer/IAvatarInfoTransformer.cs index a6ea9ebe..12e40cfa 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Transformer/IAvatarInfoTransformer.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Transformer/IAvatarInfoTransformer.cs @@ -15,5 +15,5 @@ internal interface IAvatarInfoTransformer /// /// 基底,角色Id必定存在 /// 源 - void Transform(ref Web.Enka.Model.AvatarInfo avatarInfo, TSource source); + void Transform(ref readonly Web.Enka.Model.AvatarInfo avatarInfo, TSource source); } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/View/Control/SkillPivot.xaml b/src/Snap.Hutao/Snap.Hutao/View/Control/SkillPivot.xaml index ada71d01..d3ce34f5 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Control/SkillPivot.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/Control/SkillPivot.xaml @@ -28,8 +28,8 @@ + ItemTemplate="{StaticResource SkillHeaderTemplate}" + SelectionChanged="OnSkillSelectorSegmentedSelectionChanged"/> diff --git a/src/Snap.Hutao/Snap.Hutao/View/Guide/GuideView.xaml b/src/Snap.Hutao/Snap.Hutao/View/Guide/GuideView.xaml index eb73fe46..af9c14a6 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Guide/GuideView.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/Guide/GuideView.xaml @@ -229,7 +229,7 @@ DisplayMemberPath="Name" ItemsSource="{Binding StaticResourceOptions.ImageArchives}" SelectedItem="{Binding StaticResourceOptions.ImageArchive, Mode=TwoWay}"/> - + diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/AvatarPropertyPage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/AvatarPropertyPage.xaml index 7805d551..2318da3e 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/AvatarPropertyPage.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/AvatarPropertyPage.xaml @@ -735,7 +735,7 @@ HorizontalAlignment="Right" Foreground="#FFFFFFFF" Style="{StaticResource TitleTextBlockStyle}" - Text="{Binding SelectedAvatar.Score}"/> + Text="{Binding SelectedAvatar.ScoreFormatted}"/> + Text="{Binding SelectedAvatar.CritScoreFormatted}"/> /// 评分 /// - public string Score { get; set; } = default!; + public string ScoreFormatted { get => $"{Score:F2}"; } /// /// 双爆评分 /// - public string CritScore { get; set; } = default!; + public string CritScoreFormatted { get => $"{CritScore:F2}"; } /// /// 好感度等级 @@ -109,6 +110,10 @@ internal sealed class AvatarView : INameIconSide, ICalculableSource internal uint LevelNumber { get; set; } + internal float Score { get; set; } + + internal float CritScore { get; set; } + /// public ICalculableAvatar ToCalculable() {