From 4c38bb528f3a885e397b1a1a2e5eebec826a2a6f Mon Sep 17 00:00:00 2001 From: Lightczx <1686188646@qq.com> Date: Wed, 6 Mar 2024 11:50:55 +0800 Subject: [PATCH] basic support --- .../Service/Cultivation/CultivationService.cs | 2 +- .../Factory/GachaStatisticsExtension.cs | 3 +- .../Factory/GachaStatisticsFactory.cs | 17 ++-- ...igTypeComparer.cs => GachaTypeComparer.cs} | 19 ++-- .../GachaLog/Factory/HistoryWishBuilder.cs | 5 +- .../Factory/HutaoStatisticsFactory.cs | 6 +- .../Factory/TypedWishSummaryBuilder.cs | 93 ++++++++----------- .../Service/GachaLog/GachaArchiveOperation.cs | 12 ++- .../Service/GachaLog/GachaItemSaveContext.cs | 60 ------------ .../Service/GachaLog/GachaLogFetchContext.cs | 16 +++- .../Service/GachaLog/GachaLogFetchStatus.cs | 16 ---- .../GachaLog/GachaLogHutaoCloudService.cs | 9 +- .../Service/GachaLog/GachaLogService.cs | 9 +- .../GachaLogServiceMetadataContext.cs | 78 ++++------------ .../GachaLog/IGachaLogHutaoCloudService.cs | 2 +- .../IMetadataDictionaryNameAvatarSource.cs | 9 ++ .../IMetadataDictionaryNameWeaponSource.cs | 9 ++ .../IMetadataSupportInitialization.cs | 9 ++ .../MetadataServiceContextExtension.cs | 39 ++++++-- .../ViewModel/GachaLog/HutaoCloudViewModel.cs | 2 +- .../Snap.Hutao/Web/Hutao/GachaLog/EndIds.cs | 7 ++ .../Web/Hutao/GachaLog/GachaEntry.cs | 5 + 22 files changed, 185 insertions(+), 242 deletions(-) rename src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/{GachaConfigTypeComparer.cs => GachaTypeComparer.cs} (51%) delete mode 100644 src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaItemSaveContext.cs create mode 100644 src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/IMetadataDictionaryNameAvatarSource.cs create mode 100644 src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/IMetadataDictionaryNameWeaponSource.cs create mode 100644 src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/IMetadataSupportInitialization.cs diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationService.cs index b8d72295..d3a93bfc 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationService.cs @@ -39,7 +39,7 @@ internal sealed partial class CultivationService : ICultivationService List entities = cultivationDbService.GetInventoryItemListByProjectId(projectId); List results = []; - foreach (Material meta in context.EnumerateInventroyMaterial()) + foreach (Material meta in context.EnumerateInventoryMaterial()) { InventoryItem entity = entities.SingleOrDefault(e => e.ItemId == meta.Id) ?? InventoryItem.From(projectId, meta.Id); results.Add(new(entity, meta, saveCommand)); diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/GachaStatisticsExtension.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/GachaStatisticsExtension.cs index 9663e3b1..420fa93e 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/GachaStatisticsExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/GachaStatisticsExtension.cs @@ -3,6 +3,7 @@ using Snap.Hutao.Model.Metadata.Abstraction; using Snap.Hutao.ViewModel.GachaLog; +using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Text; using Windows.UI; @@ -25,7 +26,7 @@ internal static class GachaStatisticsExtension bool isPreviousUp = true; // mark the IsGuarantee - foreach (SummaryItem item in summaryItems) + foreach (ref readonly SummaryItem item in CollectionsMarshal.AsSpan(summaryItems)) { if (item.IsUp && (!isPreviousUp)) { diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/GachaStatisticsFactory.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/GachaStatisticsFactory.cs index d484cd32..998edb50 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/GachaStatisticsFactory.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/GachaStatisticsFactory.cs @@ -7,6 +7,7 @@ using Snap.Hutao.Model.Metadata; using Snap.Hutao.Model.Metadata.Avatar; using Snap.Hutao.Model.Metadata.Weapon; using Snap.Hutao.Service.Metadata; +using Snap.Hutao.Service.Metadata.ContextAbstraction; using Snap.Hutao.ViewModel.GachaLog; using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo; using Snap.Hutao.Web.Hutao.GachaLog; @@ -31,9 +32,8 @@ internal sealed partial class GachaStatisticsFactory : IGachaStatisticsFactory public async ValueTask CreateAsync(List items, GachaLogServiceMetadataContext context) { await taskContext.SwitchToBackgroundAsync(); - List gachaEvents = await metadataService.GetGachaEventListAsync().ConfigureAwait(false); - List historyWishBuilders = gachaEvents.SelectList(gachaEvent => new HistoryWishBuilder(gachaEvent, context)); + List historyWishBuilders = context.GachaEvents.SelectList(gachaEvent => new HistoryWishBuilder(gachaEvent, context)); return CreateCore(taskContext, homaGachaLogClient, items, historyWishBuilders, context, options.IsEmptyHistoryWishVisible); } @@ -70,18 +70,19 @@ internal sealed partial class GachaStatisticsFactory : IGachaStatisticsFactory // Items are ordered by precise time, first is oldest // 'ref' is not allowed here because we have lambda below - foreach (Model.Entity.GachaItem item in CollectionsMarshal.AsSpan(items)) + foreach (ref readonly Model.Entity.GachaItem item in CollectionsMarshal.AsSpan(items)) { - // Find target history wish to operate. // w.From <= item.Time <= w.To + // Find target history wish to operate. // banner.From <= item.Time <= banner.To + Model.Entity.GachaItem pinned = item; HistoryWishBuilder? targetHistoryWishBuilder = item.GachaType is not (GachaType.Standard or GachaType.NewBie) - ? historyWishBuilderMap[item.GachaType].BinarySearch(w => item.Time < w.From ? -1 : item.Time > w.To ? 1 : 0) + ? historyWishBuilderMap[item.GachaType].BinarySearch(banner => pinned.Time < banner.From ? -1 : pinned.Time > banner.To ? 1 : 0) : default; switch (item.ItemId.StringLength()) { case 8U: { - Avatar avatar = context.IdAvatarMap[item.ItemId]; + Avatar avatar = context.GetAvatar(item.ItemId); bool isUp = false; switch (avatar.Quality) @@ -142,7 +143,7 @@ internal sealed partial class GachaStatisticsFactory : IGachaStatisticsFactory } } - AsyncBarrier barrier = new(3); + AsyncBarrier barrier = new(4); return new() { @@ -150,7 +151,7 @@ internal sealed partial class GachaStatisticsFactory : IGachaStatisticsFactory HistoryWishes = historyWishBuilders .Where(b => isEmptyHistoryWishVisible || (!b.IsEmpty)) .OrderByDescending(builder => builder.From) - .ThenBy(builder => builder.ConfigType, GachaConfigTypeComparer.Shared) + .ThenBy(builder => builder.ConfigType, GachaTypeComparer.Shared) .Select(builder => builder.ToHistoryWish()) .ToList(), diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/GachaConfigTypeComparer.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/GachaTypeComparer.cs similarity index 51% rename from src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/GachaConfigTypeComparer.cs rename to src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/GachaTypeComparer.cs index 9771397f..25f2e0d4 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/GachaConfigTypeComparer.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/GachaTypeComparer.cs @@ -10,22 +10,23 @@ namespace Snap.Hutao.Service.GachaLog.Factory; /// /// 祈愿配置类型比较器 /// -internal sealed class GachaConfigTypeComparer : IComparer +internal sealed class GachaTypeComparer : IComparer { - private static readonly Lazy LazyShared = new(() => new()); - private static readonly FrozenDictionary OrderMap = FrozenDictionary.ToFrozenDictionary( + private static readonly Lazy LazyShared = new(() => new()); + private static readonly FrozenDictionary OrderMap = FrozenDictionary.ToFrozenDictionary( [ - KeyValuePair.Create(GachaConfigType.AvatarEventWish, 0), - KeyValuePair.Create(GachaConfigType.AvatarEventWish2, 1), - KeyValuePair.Create(GachaConfigType.WeaponEventWish, 2), - KeyValuePair.Create(GachaConfigType.StandardWish, 3), - KeyValuePair.Create(GachaConfigType.NoviceWish, 4), + KeyValuePair.Create(GachaType.ActivityAvatar, 0), + KeyValuePair.Create(GachaType.SpecialActivityAvatar, 1), + KeyValuePair.Create(GachaType.ActivityWeapon, 2), + KeyValuePair.Create(GachaType.Standard, 3), + KeyValuePair.Create(GachaType.NewBie, 4), + KeyValuePair.Create(GachaType.ActivityCity, 5), ]); /// /// 共享的比较器 /// - public static GachaConfigTypeComparer Shared { get => LazyShared.Value; } + public static GachaTypeComparer Shared { get => LazyShared.Value; } /// public int Compare(GachaType x, GachaType y) diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/HistoryWishBuilder.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/HistoryWishBuilder.cs index 55166473..34ce5071 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/HistoryWishBuilder.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/HistoryWishBuilder.cs @@ -29,7 +29,6 @@ internal sealed class HistoryWishBuilder /// /// 卡池配置 /// 祈愿记录上下文 - [SuppressMessage("", "SH002")] public HistoryWishBuilder(GachaEvent gachaEvent, GachaLogServiceMetadataContext context) { this.gachaEvent = gachaEvent; @@ -112,13 +111,13 @@ internal sealed class HistoryWishBuilder { HistoryWish historyWish = new() { - // base + // Base Name = gachaEvent.Name, From = gachaEvent.From, To = gachaEvent.To, TotalCount = totalCountTracker, - // fill + // Fill Version = gachaEvent.Version, BannerImage = gachaEvent.Banner, OrangeUpList = orangeUpCounter.ToStatisticsList(), diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/HutaoStatisticsFactory.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/HutaoStatisticsFactory.cs index 1e4657a1..45fbbd70 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/HutaoStatisticsFactory.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/HutaoStatisticsFactory.cs @@ -5,6 +5,7 @@ using Snap.Hutao.Core.ExceptionService; using Snap.Hutao.Model.Intrinsic; using Snap.Hutao.Model.Metadata; using Snap.Hutao.Model.Metadata.Abstraction; +using Snap.Hutao.Service.Metadata.ContextAbstraction; using Snap.Hutao.ViewModel.GachaLog; using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo; using Snap.Hutao.Web.Hutao.GachaLog; @@ -56,12 +57,13 @@ internal sealed class HutaoStatisticsFactory { IStatisticsItemSource source = item.Item.StringLength() switch { - 8U => context.IdAvatarMap[item.Item], - 5U => context.IdWeaponMap[item.Item], + 8U => context.GetAvatar(item.Item), + 5U => context.GetWeapon(item.Item), _ => throw HutaoException.GachaStatisticsInvalidItemId(item.Item), }; StatisticsItem statisticsItem = source.ToStatisticsItem(unchecked((int)item.Count)); + // Put UP items to a separate list if (gachaEvent.UpOrangeList.Contains(item.Item) || gachaEvent.UpPurpleList.Contains(item.Item)) { upItems.Add(statisticsItem); diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/TypedWishSummaryBuilder.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/TypedWishSummaryBuilder.cs index 72e13b23..08064ae6 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/TypedWishSummaryBuilder.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/TypedWishSummaryBuilder.cs @@ -15,21 +15,6 @@ namespace Snap.Hutao.Service.GachaLog.Factory; [HighQuality] internal sealed class TypedWishSummaryBuilder { - /// - /// 常驻祈愿 - /// - public static readonly Func IsStandardWish = type => type is GachaType.Standard; - - /// - /// 角色活动 - /// - public static readonly Func IsAvatarEventWish = type => type is GachaType.ActivityAvatar or GachaType.SpecialActivityAvatar; - - /// - /// 武器活动 - /// - public static readonly Func IsWeaponEventWish = type => type is GachaType.ActivityWeapon; - private readonly TypedWishSummaryBuilderContext context; private readonly List averageOrangePullTracker = []; @@ -62,52 +47,54 @@ internal sealed class TypedWishSummaryBuilder /// 是否为Up物品 public void Track(GachaItem item, ISummaryItemSource source, bool isUp) { - if (context.TypeEvaluator(item.GachaType)) + if (!context.TypeEvaluator(item.GachaType)) { - ++lastOrangePullTracker; - ++lastPurplePullTracker; - ++lastUpOrangePullTracker; + return; + } - // track total pulls - ++totalCountTracker; - TrackFromToTime(item.Time); + ++lastOrangePullTracker; + ++lastPurplePullTracker; + ++lastUpOrangePullTracker; - switch (source.Quality) - { - case QualityType.QUALITY_ORANGE: + // track total pulls + ++totalCountTracker; + TrackFromToTime(item.Time); + + switch (source.Quality) + { + case QualityType.QUALITY_ORANGE: + { + TrackMinMaxOrangePull(lastOrangePullTracker); + averageOrangePullTracker.Add(lastOrangePullTracker); + + if (isUp) { - TrackMinMaxOrangePull(lastOrangePullTracker); - averageOrangePullTracker.Add(lastOrangePullTracker); - - if (isUp) - { - averageUpOrangePullTracker.Add(lastUpOrangePullTracker); - lastUpOrangePullTracker = 0; - } - - summaryItems.Add(source.ToSummaryItem(lastOrangePullTracker, item.Time, isUp)); - - lastOrangePullTracker = 0; - ++totalOrangePullTracker; - break; + averageUpOrangePullTracker.Add(lastUpOrangePullTracker); + lastUpOrangePullTracker = 0; } - case QualityType.QUALITY_PURPLE: - { - lastPurplePullTracker = 0; - ++totalPurplePullTracker; - break; - } + summaryItems.Add(source.ToSummaryItem(lastOrangePullTracker, item.Time, isUp)); - case QualityType.QUALITY_BLUE: - { - ++totalBluePullTracker; - break; - } - - default: + lastOrangePullTracker = 0; + ++totalOrangePullTracker; break; - } + } + + case QualityType.QUALITY_PURPLE: + { + lastPurplePullTracker = 0; + ++totalPurplePullTracker; + break; + } + + case QualityType.QUALITY_BLUE: + { + ++totalBluePullTracker; + break; + } + + default: + break; } } diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaArchiveOperation.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaArchiveOperation.cs index 6bf5dc77..70b9f085 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaArchiveOperation.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaArchiveOperation.cs @@ -15,12 +15,14 @@ internal static class GachaArchiveOperation { archive = archives.SingleOrDefault(a => a.Uid == uid); - if (archive is null) + if (archive is not null) { - GachaArchive created = GachaArchive.From(uid); - gachaLogDbService.AddGachaArchive(created); - taskContext.InvokeOnMainThread(() => archives.Add(created)); - archive = created; + return; } + + GachaArchive created = GachaArchive.From(uid); + gachaLogDbService.AddGachaArchive(created); + taskContext.InvokeOnMainThread(() => archives.Add(created)); + archive = created; } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaItemSaveContext.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaItemSaveContext.cs deleted file mode 100644 index e12e644b..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaItemSaveContext.cs +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) DGP Studio. All rights reserved. -// Licensed under the MIT license. - -using Snap.Hutao.Model.Entity; -using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo; - -namespace Snap.Hutao.Service.GachaLog; - -/// -/// 祈愿物品保存上下文 -/// -internal readonly struct GachaItemSaveContext -{ - /// - /// 待添加物品 - /// - public readonly List ItemsToAdd; - - /// - /// 是否懒惰 - /// - public readonly bool IsLazy; - - public readonly GachaType QueryType; - - /// - /// 结尾 Id - /// - public readonly long EndId; - - /// - /// 数据集 - /// - public readonly IGachaLogDbService GachaLogDbService; - - public GachaItemSaveContext(List itemsToAdd, bool isLazy, GachaType queryType, long endId, IGachaLogDbService gachaLogDbService) - { - ItemsToAdd = itemsToAdd; - IsLazy = isLazy; - QueryType = queryType; - EndId = endId; - GachaLogDbService = gachaLogDbService; - } - - public void SaveItems(GachaArchive archive) - { - if (ItemsToAdd.Count <= 0) - { - return; - } - - // 全量刷新 - if (!IsLazy) - { - GachaLogDbService.RemoveNewerGachaItemRangeByArchiveIdQueryTypeAndEndId(archive.InnerId, QueryType, EndId); - } - - GachaLogDbService.AddGachaItemRange(ItemsToAdd); - } -} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogFetchContext.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogFetchContext.cs index 871ee384..76c9137d 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogFetchContext.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogFetchContext.cs @@ -53,7 +53,7 @@ internal struct GachaLogFetchContext private readonly ITaskContext taskContext; private readonly bool isLazy; - public GachaLogFetchContext(IGachaLogDbService gachaLogDbService, ITaskContext taskContext, in GachaLogServiceMetadataContext serviceContext, bool isLazy) + public GachaLogFetchContext(IGachaLogDbService gachaLogDbService, ITaskContext taskContext, GachaLogServiceMetadataContext serviceContext, bool isLazy) { this.gachaLogDbService = gachaLogDbService; this.taskContext = taskContext; @@ -140,8 +140,18 @@ internal struct GachaLogFetchContext // While no item is fetched, archive can be null. if (TargetArchive is not null) { - GachaItemSaveContext saveContext = new(ItemsToAdd, isLazy, QueryOptions.Type, QueryOptions.EndId, gachaLogDbService); - saveContext.SaveItems(TargetArchive); + if (ItemsToAdd.Count <= 0) + { + return; + } + + // 全量刷新 + if (!isLazy) + { + gachaLogDbService.RemoveNewerGachaItemRangeByArchiveIdQueryTypeAndEndId(TargetArchive.InnerId, QueryOptions.Type, QueryOptions.EndId); + } + + gachaLogDbService.AddGachaItemRange(ItemsToAdd); } } diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogFetchStatus.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogFetchStatus.cs index 55fa83d0..6b51193a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogFetchStatus.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogFetchStatus.cs @@ -6,33 +6,17 @@ using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo; namespace Snap.Hutao.Service.GachaLog; -/// -/// 祈愿记录获取状态 -/// internal sealed class GachaLogFetchStatus { - /// - /// 构造一个新的祈愿记录获取状态 - /// - /// 卡池类型 public GachaLogFetchStatus(GachaType configType) { ConfigType = configType; } - /// - /// 验证密钥是否过期 - /// public bool AuthKeyTimeout { get; set; } - /// - /// 卡池类型 - /// public GachaType ConfigType { get; set; } - /// - /// 当前获取的物品 - /// public List Items { get; set; } = new(20); public string Header diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogHutaoCloudService.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogHutaoCloudService.cs index 232eb10b..dfeffede 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogHutaoCloudService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogHutaoCloudService.cs @@ -56,14 +56,16 @@ internal sealed partial class GachaLogHutaoCloudService : IGachaLogHutaoCloudSer } /// - public async ValueTask> RetrieveGachaItemsAsync(string uid, CancellationToken token = default) + public async ValueTask> RetrieveGachaArchiveIdAsync(string uid, CancellationToken token = default) { GachaArchive? archive = await gachaLogDbService .GetGachaArchiveByUidAsync(uid, token) .ConfigureAwait(false); EndIds endIds = await CreateEndIdsAsync(archive, token).ConfigureAwait(false); - Response> resp = await homaGachaLogClient.RetrieveGachaItemsAsync(uid, endIds, token).ConfigureAwait(false); + Response> resp = await homaGachaLogClient + .RetrieveGachaItemsAsync(uid, endIds, token) + .ConfigureAwait(false); if (!resp.IsOk()) { @@ -76,7 +78,8 @@ internal sealed partial class GachaLogHutaoCloudService : IGachaLogHutaoCloudSer await gachaLogDbService.AddGachaArchiveAsync(archive).ConfigureAwait(false); } - List gachaItems = resp.Data.SelectList(i => Model.Entity.GachaItem.From(archive.InnerId, i)); + Guid archiveId = archive.InnerId; + List gachaItems = resp.Data.SelectList(i => Model.Entity.GachaItem.From(archiveId, i)); await gachaLogDbService.AddGachaItemsAsync(gachaItems).ConfigureAwait(false); return new(true, archive.InnerId); } diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogService.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogService.cs index d6a86465..9e1cd8e4 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogService.cs @@ -9,6 +9,7 @@ using Snap.Hutao.Model.Primitive; using Snap.Hutao.Service.GachaLog.Factory; using Snap.Hutao.Service.GachaLog.QueryProvider; using Snap.Hutao.Service.Metadata; +using Snap.Hutao.Service.Metadata.ContextAbstraction; using Snap.Hutao.ViewModel.GachaLog; using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo; using Snap.Hutao.Web.Response; @@ -62,13 +63,7 @@ internal sealed partial class GachaLogService : IGachaLogService if (await metadataService.InitializeAsync().ConfigureAwait(false)) { - Dictionary idAvatarMap = await metadataService.GetIdToAvatarMapAsync(token).ConfigureAwait(false); - Dictionary idWeaponMap = await metadataService.GetIdToWeaponMapAsync(token).ConfigureAwait(false); - - Dictionary nameAvatarMap = await metadataService.GetNameToAvatarMapAsync(token).ConfigureAwait(false); - Dictionary nameWeaponMap = await metadataService.GetNameToWeaponMapAsync(token).ConfigureAwait(false); - context = new(idAvatarMap, idWeaponMap, nameAvatarMap, nameWeaponMap); - + context = await metadataService.GetContextAsync(token).ConfigureAwait(false); ArchiveCollection = gachaLogDbService.GetGachaArchiveCollection(); return true; } diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogServiceMetadataContext.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogServiceMetadataContext.cs index 749903fc..26a2665a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogServiceMetadataContext.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogServiceMetadataContext.cs @@ -2,10 +2,12 @@ // Licensed under the MIT license. using Snap.Hutao.Model; +using Snap.Hutao.Model.Metadata; using Snap.Hutao.Model.Metadata.Abstraction; using Snap.Hutao.Model.Metadata.Avatar; using Snap.Hutao.Model.Metadata.Weapon; using Snap.Hutao.Model.Primitive; +using Snap.Hutao.Service.Metadata.ContextAbstraction; using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo; namespace Snap.Hutao.Service.GachaLog; @@ -13,65 +15,28 @@ namespace Snap.Hutao.Service.GachaLog; /// /// 祈愿记录服务上下文 /// -internal readonly struct GachaLogServiceMetadataContext +internal sealed class GachaLogServiceMetadataContext : IMetadataContext, + IMetadataSupportInitialization, + IMetadataListGachaEventSource, + IMetadataDictionaryIdAvatarSource, + IMetadataDictionaryIdWeaponSource, + IMetadataDictionaryNameAvatarSource, + IMetadataDictionaryNameWeaponSource { - /// - /// 物品缓存 - /// - public readonly Dictionary ItemCache = []; + public Dictionary ItemCache { get; set; } = []; - /// - /// Id 角色 映射 - /// - public readonly Dictionary IdAvatarMap; + public List GachaEvents { get; set; } = default!; - /// - /// Id 武器 映射 - /// - public readonly Dictionary IdWeaponMap; + public Dictionary IdAvatarMap { get; set; } = default!; - /// - /// 名称 角色 映射 - /// - public readonly Dictionary NameAvatarMap; + public Dictionary IdWeaponMap { get; set; } = default!; - /// - /// 名称 武器 映射 - /// - public readonly Dictionary NameWeaponMap; + public Dictionary NameAvatarMap { get; set; } = default!; - /// - /// 是否初始化完成 - /// - public readonly bool IsInitialized; + public Dictionary NameWeaponMap { get; set; } = default!; - /// - /// 构造一个新的祈愿记录服务上下文 - /// - /// Id 角色 映射 - /// Id 武器 映射 - /// 名称 角色 映射 - /// 名称 武器 映射 - public GachaLogServiceMetadataContext( - Dictionary idAvatarMap, - Dictionary idWeaponMap, - Dictionary nameAvatarMap, - Dictionary nameWeaponMap) - { - IdAvatarMap = idAvatarMap; - IdWeaponMap = idWeaponMap; - NameAvatarMap = nameAvatarMap; - NameWeaponMap = nameWeaponMap; + public bool IsInitialized { get; set; } - IsInitialized = true; - } - - /// - /// 按名称获取物品 - /// - /// 名称 - /// 类型 - /// 物品 public Item GetItemByNameAndType(string name, string type) { if (!ItemCache.TryGetValue(name, out Item? result)) @@ -93,11 +58,6 @@ internal readonly struct GachaLogServiceMetadataContext return result; } - /// - /// 按物品 Id 获取名称星级 - /// - /// Id - /// 名称星级 public INameQuality GetNameQualityByItemId(uint id) { uint place = id.StringLength(); @@ -109,12 +69,6 @@ internal readonly struct GachaLogServiceMetadataContext }; } - /// - /// 获取物品 Id - /// O(1) - /// - /// 祈愿物品 - /// 物品 Id public uint GetItemId(GachaLogItem item) { if (item.ItemType == SH.ModelInterchangeUIGFItemTypeAvatar) diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/IGachaLogHutaoCloudService.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/IGachaLogHutaoCloudService.cs index 18fc51ce..c000e23a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/IGachaLogHutaoCloudService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/IGachaLogHutaoCloudService.cs @@ -36,7 +36,7 @@ internal interface IGachaLogHutaoCloudService /// uid /// 取消令牌 /// 是否获取成功 - ValueTask> RetrieveGachaItemsAsync(string uid, CancellationToken token = default); + ValueTask> RetrieveGachaArchiveIdAsync(string uid, CancellationToken token = default); /// /// 异步上传祈愿记录 diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/IMetadataDictionaryNameAvatarSource.cs b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/IMetadataDictionaryNameAvatarSource.cs new file mode 100644 index 00000000..88ecf91d --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/IMetadataDictionaryNameAvatarSource.cs @@ -0,0 +1,9 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +namespace Snap.Hutao.Service.Metadata.ContextAbstraction; + +internal interface IMetadataDictionaryNameAvatarSource +{ + public Dictionary NameAvatarMap { get; set; } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/IMetadataDictionaryNameWeaponSource.cs b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/IMetadataDictionaryNameWeaponSource.cs new file mode 100644 index 00000000..34b69054 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/IMetadataDictionaryNameWeaponSource.cs @@ -0,0 +1,9 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +namespace Snap.Hutao.Service.Metadata.ContextAbstraction; + +internal interface IMetadataDictionaryNameWeaponSource +{ + public Dictionary NameWeaponMap { get; set; } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/IMetadataSupportInitialization.cs b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/IMetadataSupportInitialization.cs new file mode 100644 index 00000000..27ee8318 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/IMetadataSupportInitialization.cs @@ -0,0 +1,9 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +namespace Snap.Hutao.Service.Metadata.ContextAbstraction; + +internal interface IMetadataSupportInitialization +{ + bool IsInitialized { get; set; } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/MetadataServiceContextExtension.cs b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/MetadataServiceContextExtension.cs index e0db64dd..f511bc7a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/MetadataServiceContextExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/MetadataServiceContextExtension.cs @@ -30,27 +30,42 @@ internal static class MetadataServiceContextExtension // Dictionary { - if (context is IMetadataDictionaryIdAvatarSource dictionaryAvatarSource) + if (context is IMetadataDictionaryIdAvatarSource dictionaryIdAvatarSource) { - dictionaryAvatarSource.IdAvatarMap = await metadataService.GetIdToAvatarMapAsync(token).ConfigureAwait(false); + dictionaryIdAvatarSource.IdAvatarMap = await metadataService.GetIdToAvatarMapAsync(token).ConfigureAwait(false); } - if (context is IMetadataDictionaryIdMaterialSource dictionaryMaterialSource) + if (context is IMetadataDictionaryIdMaterialSource dictionaryIdMaterialSource) { - dictionaryMaterialSource.IdMaterialMap = await metadataService.GetIdToMaterialMapAsync(token).ConfigureAwait(false); + dictionaryIdMaterialSource.IdMaterialMap = await metadataService.GetIdToMaterialMapAsync(token).ConfigureAwait(false); } - if (context is IMetadataDictionaryIdWeaponSource dictionaryWeaponSource) + if (context is IMetadataDictionaryIdWeaponSource dictionaryIdWeaponSource) { - dictionaryWeaponSource.IdWeaponMap = await metadataService.GetIdToWeaponMapAsync(token).ConfigureAwait(false); + dictionaryIdWeaponSource.IdWeaponMap = await metadataService.GetIdToWeaponMapAsync(token).ConfigureAwait(false); } + + if (context is IMetadataDictionaryNameAvatarSource dictionaryNameAvatarSource) + { + dictionaryNameAvatarSource.NameAvatarMap = await metadataService.GetNameToAvatarMapAsync(token).ConfigureAwait(false); + } + + if (context is IMetadataDictionaryNameWeaponSource dictionaryNameWeaponSource) + { + dictionaryNameWeaponSource.NameWeaponMap = await metadataService.GetNameToWeaponMapAsync(token).ConfigureAwait(false); + } + } + + if (context is IMetadataSupportInitialization supportInitialization) + { + supportInitialization.IsInitialized = true; } return context; } #pragma warning disable SH002 - public static IEnumerable EnumerateInventroyMaterial(this IMetadataListMaterialSource context) + public static IEnumerable EnumerateInventoryMaterial(this IMetadataListMaterialSource context) { return context.Materials.Where(m => m.IsInventoryItem()).OrderBy(m => m.Id.Value); } @@ -60,6 +75,11 @@ internal static class MetadataServiceContextExtension return context.IdAvatarMap[id]; } + public static Avatar GetAvatar(this IMetadataDictionaryNameAvatarSource context, string name) + { + return context.NameAvatarMap[name]; + } + public static Material GetMaterial(this IMetadataDictionaryIdMaterialSource context, MaterialId id) { return context.IdMaterialMap[id]; @@ -69,5 +89,10 @@ internal static class MetadataServiceContextExtension { return context.IdWeaponMap[id]; } + + public static Weapon GetWeapon(this IMetadataDictionaryNameWeaponSource context, string name) + { + return context.NameWeaponMap[name]; + } #pragma warning restore SH002 } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLog/HutaoCloudViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLog/HutaoCloudViewModel.cs index 890282ab..6829162d 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLog/HutaoCloudViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLog/HutaoCloudViewModel.cs @@ -60,7 +60,7 @@ internal sealed partial class HutaoCloudViewModel : Abstraction.ViewModel using (await dialog.BlockAsync(taskContext).ConfigureAwait(false)) { - return await hutaoCloudService.RetrieveGachaItemsAsync(uid).ConfigureAwait(false); + return await hutaoCloudService.RetrieveGachaArchiveIdAsync(uid).ConfigureAwait(false); } } diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/GachaLog/EndIds.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/GachaLog/EndIds.cs index 07baf4a5..e5274ce8 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/GachaLog/EndIds.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/GachaLog/EndIds.cs @@ -34,6 +34,12 @@ internal sealed class EndIds [JsonPropertyName("302")] public long WeaponEventWish { get; set; } + /// + /// 集录祈愿 + /// + [JsonPropertyName("500")] + public long ChronicledWish { get; set; } + /// /// 获取 Last Id /// @@ -83,5 +89,6 @@ internal sealed class EndIds yield return new(GachaType.Standard, StandardWish); yield return new(GachaType.ActivityAvatar, AvatarEventWish); yield return new(GachaType.ActivityWeapon, WeaponEventWish); + yield return new(GachaType.ActivityCity, ChronicledWish); } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/GachaLog/GachaEntry.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/GachaLog/GachaEntry.cs index ab18eb88..30187115 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/GachaLog/GachaEntry.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/GachaLog/GachaEntry.cs @@ -10,6 +10,11 @@ internal sealed class GachaEntry /// public string Uid { get; set; } = default!; + /// + /// 是否被排除出了全球统计 + /// + public bool Excluded { get; set; } + /// /// 物品个数 ///