mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
basic support
This commit is contained in:
@@ -39,7 +39,7 @@ internal sealed partial class CultivationService : ICultivationService
|
|||||||
List<InventoryItem> entities = cultivationDbService.GetInventoryItemListByProjectId(projectId);
|
List<InventoryItem> entities = cultivationDbService.GetInventoryItemListByProjectId(projectId);
|
||||||
|
|
||||||
List<InventoryItemView> results = [];
|
List<InventoryItemView> 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);
|
InventoryItem entity = entities.SingleOrDefault(e => e.ItemId == meta.Id) ?? InventoryItem.From(projectId, meta.Id);
|
||||||
results.Add(new(entity, meta, saveCommand));
|
results.Add(new(entity, meta, saveCommand));
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using Snap.Hutao.Model.Metadata.Abstraction;
|
using Snap.Hutao.Model.Metadata.Abstraction;
|
||||||
using Snap.Hutao.ViewModel.GachaLog;
|
using Snap.Hutao.ViewModel.GachaLog;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Windows.UI;
|
using Windows.UI;
|
||||||
@@ -25,7 +26,7 @@ internal static class GachaStatisticsExtension
|
|||||||
bool isPreviousUp = true;
|
bool isPreviousUp = true;
|
||||||
|
|
||||||
// mark the IsGuarantee
|
// mark the IsGuarantee
|
||||||
foreach (SummaryItem item in summaryItems)
|
foreach (ref readonly SummaryItem item in CollectionsMarshal.AsSpan(summaryItems))
|
||||||
{
|
{
|
||||||
if (item.IsUp && (!isPreviousUp))
|
if (item.IsUp && (!isPreviousUp))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using Snap.Hutao.Model.Metadata;
|
|||||||
using Snap.Hutao.Model.Metadata.Avatar;
|
using Snap.Hutao.Model.Metadata.Avatar;
|
||||||
using Snap.Hutao.Model.Metadata.Weapon;
|
using Snap.Hutao.Model.Metadata.Weapon;
|
||||||
using Snap.Hutao.Service.Metadata;
|
using Snap.Hutao.Service.Metadata;
|
||||||
|
using Snap.Hutao.Service.Metadata.ContextAbstraction;
|
||||||
using Snap.Hutao.ViewModel.GachaLog;
|
using Snap.Hutao.ViewModel.GachaLog;
|
||||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||||
using Snap.Hutao.Web.Hutao.GachaLog;
|
using Snap.Hutao.Web.Hutao.GachaLog;
|
||||||
@@ -31,9 +32,8 @@ internal sealed partial class GachaStatisticsFactory : IGachaStatisticsFactory
|
|||||||
public async ValueTask<GachaStatistics> CreateAsync(List<Model.Entity.GachaItem> items, GachaLogServiceMetadataContext context)
|
public async ValueTask<GachaStatistics> CreateAsync(List<Model.Entity.GachaItem> items, GachaLogServiceMetadataContext context)
|
||||||
{
|
{
|
||||||
await taskContext.SwitchToBackgroundAsync();
|
await taskContext.SwitchToBackgroundAsync();
|
||||||
List<GachaEvent> gachaEvents = await metadataService.GetGachaEventListAsync().ConfigureAwait(false);
|
|
||||||
List<HistoryWishBuilder> historyWishBuilders = gachaEvents.SelectList(gachaEvent => new HistoryWishBuilder(gachaEvent, context));
|
|
||||||
|
|
||||||
|
List<HistoryWishBuilder> historyWishBuilders = context.GachaEvents.SelectList(gachaEvent => new HistoryWishBuilder(gachaEvent, context));
|
||||||
return CreateCore(taskContext, homaGachaLogClient, items, historyWishBuilders, context, options.IsEmptyHistoryWishVisible);
|
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
|
// Items are ordered by precise time, first is oldest
|
||||||
// 'ref' is not allowed here because we have lambda below
|
// '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)
|
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;
|
: default;
|
||||||
|
|
||||||
switch (item.ItemId.StringLength())
|
switch (item.ItemId.StringLength())
|
||||||
{
|
{
|
||||||
case 8U:
|
case 8U:
|
||||||
{
|
{
|
||||||
Avatar avatar = context.IdAvatarMap[item.ItemId];
|
Avatar avatar = context.GetAvatar(item.ItemId);
|
||||||
|
|
||||||
bool isUp = false;
|
bool isUp = false;
|
||||||
switch (avatar.Quality)
|
switch (avatar.Quality)
|
||||||
@@ -142,7 +143,7 @@ internal sealed partial class GachaStatisticsFactory : IGachaStatisticsFactory
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AsyncBarrier barrier = new(3);
|
AsyncBarrier barrier = new(4);
|
||||||
|
|
||||||
return new()
|
return new()
|
||||||
{
|
{
|
||||||
@@ -150,7 +151,7 @@ internal sealed partial class GachaStatisticsFactory : IGachaStatisticsFactory
|
|||||||
HistoryWishes = historyWishBuilders
|
HistoryWishes = historyWishBuilders
|
||||||
.Where(b => isEmptyHistoryWishVisible || (!b.IsEmpty))
|
.Where(b => isEmptyHistoryWishVisible || (!b.IsEmpty))
|
||||||
.OrderByDescending(builder => builder.From)
|
.OrderByDescending(builder => builder.From)
|
||||||
.ThenBy(builder => builder.ConfigType, GachaConfigTypeComparer.Shared)
|
.ThenBy(builder => builder.ConfigType, GachaTypeComparer.Shared)
|
||||||
.Select(builder => builder.ToHistoryWish())
|
.Select(builder => builder.ToHistoryWish())
|
||||||
.ToList(),
|
.ToList(),
|
||||||
|
|
||||||
|
|||||||
@@ -10,22 +10,23 @@ namespace Snap.Hutao.Service.GachaLog.Factory;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 祈愿配置类型比较器
|
/// 祈愿配置类型比较器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal sealed class GachaConfigTypeComparer : IComparer<GachaType>
|
internal sealed class GachaTypeComparer : IComparer<GachaType>
|
||||||
{
|
{
|
||||||
private static readonly Lazy<GachaConfigTypeComparer> LazyShared = new(() => new());
|
private static readonly Lazy<GachaTypeComparer> LazyShared = new(() => new());
|
||||||
private static readonly FrozenDictionary<GachaConfigType, int> OrderMap = FrozenDictionary.ToFrozenDictionary(
|
private static readonly FrozenDictionary<GachaType, int> OrderMap = FrozenDictionary.ToFrozenDictionary(
|
||||||
[
|
[
|
||||||
KeyValuePair.Create(GachaConfigType.AvatarEventWish, 0),
|
KeyValuePair.Create(GachaType.ActivityAvatar, 0),
|
||||||
KeyValuePair.Create(GachaConfigType.AvatarEventWish2, 1),
|
KeyValuePair.Create(GachaType.SpecialActivityAvatar, 1),
|
||||||
KeyValuePair.Create(GachaConfigType.WeaponEventWish, 2),
|
KeyValuePair.Create(GachaType.ActivityWeapon, 2),
|
||||||
KeyValuePair.Create(GachaConfigType.StandardWish, 3),
|
KeyValuePair.Create(GachaType.Standard, 3),
|
||||||
KeyValuePair.Create(GachaConfigType.NoviceWish, 4),
|
KeyValuePair.Create(GachaType.NewBie, 4),
|
||||||
|
KeyValuePair.Create(GachaType.ActivityCity, 5),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 共享的比较器
|
/// 共享的比较器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static GachaConfigTypeComparer Shared { get => LazyShared.Value; }
|
public static GachaTypeComparer Shared { get => LazyShared.Value; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public int Compare(GachaType x, GachaType y)
|
public int Compare(GachaType x, GachaType y)
|
||||||
@@ -29,7 +29,6 @@ internal sealed class HistoryWishBuilder
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="gachaEvent">卡池配置</param>
|
/// <param name="gachaEvent">卡池配置</param>
|
||||||
/// <param name="context">祈愿记录上下文</param>
|
/// <param name="context">祈愿记录上下文</param>
|
||||||
[SuppressMessage("", "SH002")]
|
|
||||||
public HistoryWishBuilder(GachaEvent gachaEvent, GachaLogServiceMetadataContext context)
|
public HistoryWishBuilder(GachaEvent gachaEvent, GachaLogServiceMetadataContext context)
|
||||||
{
|
{
|
||||||
this.gachaEvent = gachaEvent;
|
this.gachaEvent = gachaEvent;
|
||||||
@@ -112,13 +111,13 @@ internal sealed class HistoryWishBuilder
|
|||||||
{
|
{
|
||||||
HistoryWish historyWish = new()
|
HistoryWish historyWish = new()
|
||||||
{
|
{
|
||||||
// base
|
// Base
|
||||||
Name = gachaEvent.Name,
|
Name = gachaEvent.Name,
|
||||||
From = gachaEvent.From,
|
From = gachaEvent.From,
|
||||||
To = gachaEvent.To,
|
To = gachaEvent.To,
|
||||||
TotalCount = totalCountTracker,
|
TotalCount = totalCountTracker,
|
||||||
|
|
||||||
// fill
|
// Fill
|
||||||
Version = gachaEvent.Version,
|
Version = gachaEvent.Version,
|
||||||
BannerImage = gachaEvent.Banner,
|
BannerImage = gachaEvent.Banner,
|
||||||
OrangeUpList = orangeUpCounter.ToStatisticsList(),
|
OrangeUpList = orangeUpCounter.ToStatisticsList(),
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using Snap.Hutao.Core.ExceptionService;
|
|||||||
using Snap.Hutao.Model.Intrinsic;
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
using Snap.Hutao.Model.Metadata;
|
using Snap.Hutao.Model.Metadata;
|
||||||
using Snap.Hutao.Model.Metadata.Abstraction;
|
using Snap.Hutao.Model.Metadata.Abstraction;
|
||||||
|
using Snap.Hutao.Service.Metadata.ContextAbstraction;
|
||||||
using Snap.Hutao.ViewModel.GachaLog;
|
using Snap.Hutao.ViewModel.GachaLog;
|
||||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||||
using Snap.Hutao.Web.Hutao.GachaLog;
|
using Snap.Hutao.Web.Hutao.GachaLog;
|
||||||
@@ -56,12 +57,13 @@ internal sealed class HutaoStatisticsFactory
|
|||||||
{
|
{
|
||||||
IStatisticsItemSource source = item.Item.StringLength() switch
|
IStatisticsItemSource source = item.Item.StringLength() switch
|
||||||
{
|
{
|
||||||
8U => context.IdAvatarMap[item.Item],
|
8U => context.GetAvatar(item.Item),
|
||||||
5U => context.IdWeaponMap[item.Item],
|
5U => context.GetWeapon(item.Item),
|
||||||
_ => throw HutaoException.GachaStatisticsInvalidItemId(item.Item),
|
_ => throw HutaoException.GachaStatisticsInvalidItemId(item.Item),
|
||||||
};
|
};
|
||||||
StatisticsItem statisticsItem = source.ToStatisticsItem(unchecked((int)item.Count));
|
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))
|
if (gachaEvent.UpOrangeList.Contains(item.Item) || gachaEvent.UpPurpleList.Contains(item.Item))
|
||||||
{
|
{
|
||||||
upItems.Add(statisticsItem);
|
upItems.Add(statisticsItem);
|
||||||
|
|||||||
@@ -15,21 +15,6 @@ namespace Snap.Hutao.Service.GachaLog.Factory;
|
|||||||
[HighQuality]
|
[HighQuality]
|
||||||
internal sealed class TypedWishSummaryBuilder
|
internal sealed class TypedWishSummaryBuilder
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// 常驻祈愿
|
|
||||||
/// </summary>
|
|
||||||
public static readonly Func<GachaType, bool> IsStandardWish = type => type is GachaType.Standard;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 角色活动
|
|
||||||
/// </summary>
|
|
||||||
public static readonly Func<GachaType, bool> IsAvatarEventWish = type => type is GachaType.ActivityAvatar or GachaType.SpecialActivityAvatar;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 武器活动
|
|
||||||
/// </summary>
|
|
||||||
public static readonly Func<GachaType, bool> IsWeaponEventWish = type => type is GachaType.ActivityWeapon;
|
|
||||||
|
|
||||||
private readonly TypedWishSummaryBuilderContext context;
|
private readonly TypedWishSummaryBuilderContext context;
|
||||||
|
|
||||||
private readonly List<int> averageOrangePullTracker = [];
|
private readonly List<int> averageOrangePullTracker = [];
|
||||||
@@ -62,52 +47,54 @@ internal sealed class TypedWishSummaryBuilder
|
|||||||
/// <param name="isUp">是否为Up物品</param>
|
/// <param name="isUp">是否为Up物品</param>
|
||||||
public void Track(GachaItem item, ISummaryItemSource source, bool isUp)
|
public void Track(GachaItem item, ISummaryItemSource source, bool isUp)
|
||||||
{
|
{
|
||||||
if (context.TypeEvaluator(item.GachaType))
|
if (!context.TypeEvaluator(item.GachaType))
|
||||||
{
|
{
|
||||||
++lastOrangePullTracker;
|
return;
|
||||||
++lastPurplePullTracker;
|
}
|
||||||
++lastUpOrangePullTracker;
|
|
||||||
|
|
||||||
// track total pulls
|
++lastOrangePullTracker;
|
||||||
++totalCountTracker;
|
++lastPurplePullTracker;
|
||||||
TrackFromToTime(item.Time);
|
++lastUpOrangePullTracker;
|
||||||
|
|
||||||
switch (source.Quality)
|
// track total pulls
|
||||||
{
|
++totalCountTracker;
|
||||||
case QualityType.QUALITY_ORANGE:
|
TrackFromToTime(item.Time);
|
||||||
|
|
||||||
|
switch (source.Quality)
|
||||||
|
{
|
||||||
|
case QualityType.QUALITY_ORANGE:
|
||||||
|
{
|
||||||
|
TrackMinMaxOrangePull(lastOrangePullTracker);
|
||||||
|
averageOrangePullTracker.Add(lastOrangePullTracker);
|
||||||
|
|
||||||
|
if (isUp)
|
||||||
{
|
{
|
||||||
TrackMinMaxOrangePull(lastOrangePullTracker);
|
averageUpOrangePullTracker.Add(lastUpOrangePullTracker);
|
||||||
averageOrangePullTracker.Add(lastOrangePullTracker);
|
lastUpOrangePullTracker = 0;
|
||||||
|
|
||||||
if (isUp)
|
|
||||||
{
|
|
||||||
averageUpOrangePullTracker.Add(lastUpOrangePullTracker);
|
|
||||||
lastUpOrangePullTracker = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
summaryItems.Add(source.ToSummaryItem(lastOrangePullTracker, item.Time, isUp));
|
|
||||||
|
|
||||||
lastOrangePullTracker = 0;
|
|
||||||
++totalOrangePullTracker;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case QualityType.QUALITY_PURPLE:
|
summaryItems.Add(source.ToSummaryItem(lastOrangePullTracker, item.Time, isUp));
|
||||||
{
|
|
||||||
lastPurplePullTracker = 0;
|
|
||||||
++totalPurplePullTracker;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case QualityType.QUALITY_BLUE:
|
lastOrangePullTracker = 0;
|
||||||
{
|
++totalOrangePullTracker;
|
||||||
++totalBluePullTracker;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case QualityType.QUALITY_PURPLE:
|
||||||
|
{
|
||||||
|
lastPurplePullTracker = 0;
|
||||||
|
++totalPurplePullTracker;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case QualityType.QUALITY_BLUE:
|
||||||
|
{
|
||||||
|
++totalBluePullTracker;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,12 +15,14 @@ internal static class GachaArchiveOperation
|
|||||||
{
|
{
|
||||||
archive = archives.SingleOrDefault(a => a.Uid == uid);
|
archive = archives.SingleOrDefault(a => a.Uid == uid);
|
||||||
|
|
||||||
if (archive is null)
|
if (archive is not null)
|
||||||
{
|
{
|
||||||
GachaArchive created = GachaArchive.From(uid);
|
return;
|
||||||
gachaLogDbService.AddGachaArchive(created);
|
|
||||||
taskContext.InvokeOnMainThread(() => archives.Add(created));
|
|
||||||
archive = created;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GachaArchive created = GachaArchive.From(uid);
|
||||||
|
gachaLogDbService.AddGachaArchive(created);
|
||||||
|
taskContext.InvokeOnMainThread(() => archives.Add(created));
|
||||||
|
archive = created;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 祈愿物品保存上下文
|
|
||||||
/// </summary>
|
|
||||||
internal readonly struct GachaItemSaveContext
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 待添加物品
|
|
||||||
/// </summary>
|
|
||||||
public readonly List<GachaItem> ItemsToAdd;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否懒惰
|
|
||||||
/// </summary>
|
|
||||||
public readonly bool IsLazy;
|
|
||||||
|
|
||||||
public readonly GachaType QueryType;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 结尾 Id
|
|
||||||
/// </summary>
|
|
||||||
public readonly long EndId;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 数据集
|
|
||||||
/// </summary>
|
|
||||||
public readonly IGachaLogDbService GachaLogDbService;
|
|
||||||
|
|
||||||
public GachaItemSaveContext(List<GachaItem> 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -53,7 +53,7 @@ internal struct GachaLogFetchContext
|
|||||||
private readonly ITaskContext taskContext;
|
private readonly ITaskContext taskContext;
|
||||||
private readonly bool isLazy;
|
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.gachaLogDbService = gachaLogDbService;
|
||||||
this.taskContext = taskContext;
|
this.taskContext = taskContext;
|
||||||
@@ -140,8 +140,18 @@ internal struct GachaLogFetchContext
|
|||||||
// While no item is fetched, archive can be null.
|
// While no item is fetched, archive can be null.
|
||||||
if (TargetArchive is not null)
|
if (TargetArchive is not null)
|
||||||
{
|
{
|
||||||
GachaItemSaveContext saveContext = new(ItemsToAdd, isLazy, QueryOptions.Type, QueryOptions.EndId, gachaLogDbService);
|
if (ItemsToAdd.Count <= 0)
|
||||||
saveContext.SaveItems(TargetArchive);
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 全量刷新
|
||||||
|
if (!isLazy)
|
||||||
|
{
|
||||||
|
gachaLogDbService.RemoveNewerGachaItemRangeByArchiveIdQueryTypeAndEndId(TargetArchive.InnerId, QueryOptions.Type, QueryOptions.EndId);
|
||||||
|
}
|
||||||
|
|
||||||
|
gachaLogDbService.AddGachaItemRange(ItemsToAdd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,33 +6,17 @@ using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
|||||||
|
|
||||||
namespace Snap.Hutao.Service.GachaLog;
|
namespace Snap.Hutao.Service.GachaLog;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 祈愿记录获取状态
|
|
||||||
/// </summary>
|
|
||||||
internal sealed class GachaLogFetchStatus
|
internal sealed class GachaLogFetchStatus
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// 构造一个新的祈愿记录获取状态
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="configType">卡池类型</param>
|
|
||||||
public GachaLogFetchStatus(GachaType configType)
|
public GachaLogFetchStatus(GachaType configType)
|
||||||
{
|
{
|
||||||
ConfigType = configType;
|
ConfigType = configType;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 验证密钥是否过期
|
|
||||||
/// </summary>
|
|
||||||
public bool AuthKeyTimeout { get; set; }
|
public bool AuthKeyTimeout { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 卡池类型
|
|
||||||
/// </summary>
|
|
||||||
public GachaType ConfigType { get; set; }
|
public GachaType ConfigType { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 当前获取的物品
|
|
||||||
/// </summary>
|
|
||||||
public List<Item> Items { get; set; } = new(20);
|
public List<Item> Items { get; set; } = new(20);
|
||||||
|
|
||||||
public string Header
|
public string Header
|
||||||
|
|||||||
@@ -56,14 +56,16 @@ internal sealed partial class GachaLogHutaoCloudService : IGachaLogHutaoCloudSer
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async ValueTask<ValueResult<bool, Guid>> RetrieveGachaItemsAsync(string uid, CancellationToken token = default)
|
public async ValueTask<ValueResult<bool, Guid>> RetrieveGachaArchiveIdAsync(string uid, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
GachaArchive? archive = await gachaLogDbService
|
GachaArchive? archive = await gachaLogDbService
|
||||||
.GetGachaArchiveByUidAsync(uid, token)
|
.GetGachaArchiveByUidAsync(uid, token)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
EndIds endIds = await CreateEndIdsAsync(archive, token).ConfigureAwait(false);
|
EndIds endIds = await CreateEndIdsAsync(archive, token).ConfigureAwait(false);
|
||||||
Response<List<Web.Hutao.GachaLog.GachaItem>> resp = await homaGachaLogClient.RetrieveGachaItemsAsync(uid, endIds, token).ConfigureAwait(false);
|
Response<List<Web.Hutao.GachaLog.GachaItem>> resp = await homaGachaLogClient
|
||||||
|
.RetrieveGachaItemsAsync(uid, endIds, token)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
if (!resp.IsOk())
|
if (!resp.IsOk())
|
||||||
{
|
{
|
||||||
@@ -76,7 +78,8 @@ internal sealed partial class GachaLogHutaoCloudService : IGachaLogHutaoCloudSer
|
|||||||
await gachaLogDbService.AddGachaArchiveAsync(archive).ConfigureAwait(false);
|
await gachaLogDbService.AddGachaArchiveAsync(archive).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Model.Entity.GachaItem> gachaItems = resp.Data.SelectList(i => Model.Entity.GachaItem.From(archive.InnerId, i));
|
Guid archiveId = archive.InnerId;
|
||||||
|
List<Model.Entity.GachaItem> gachaItems = resp.Data.SelectList(i => Model.Entity.GachaItem.From(archiveId, i));
|
||||||
await gachaLogDbService.AddGachaItemsAsync(gachaItems).ConfigureAwait(false);
|
await gachaLogDbService.AddGachaItemsAsync(gachaItems).ConfigureAwait(false);
|
||||||
return new(true, archive.InnerId);
|
return new(true, archive.InnerId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ using Snap.Hutao.Model.Primitive;
|
|||||||
using Snap.Hutao.Service.GachaLog.Factory;
|
using Snap.Hutao.Service.GachaLog.Factory;
|
||||||
using Snap.Hutao.Service.GachaLog.QueryProvider;
|
using Snap.Hutao.Service.GachaLog.QueryProvider;
|
||||||
using Snap.Hutao.Service.Metadata;
|
using Snap.Hutao.Service.Metadata;
|
||||||
|
using Snap.Hutao.Service.Metadata.ContextAbstraction;
|
||||||
using Snap.Hutao.ViewModel.GachaLog;
|
using Snap.Hutao.ViewModel.GachaLog;
|
||||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||||
using Snap.Hutao.Web.Response;
|
using Snap.Hutao.Web.Response;
|
||||||
@@ -62,13 +63,7 @@ internal sealed partial class GachaLogService : IGachaLogService
|
|||||||
|
|
||||||
if (await metadataService.InitializeAsync().ConfigureAwait(false))
|
if (await metadataService.InitializeAsync().ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
Dictionary<AvatarId, Model.Metadata.Avatar.Avatar> idAvatarMap = await metadataService.GetIdToAvatarMapAsync(token).ConfigureAwait(false);
|
context = await metadataService.GetContextAsync<GachaLogServiceMetadataContext>(token).ConfigureAwait(false);
|
||||||
Dictionary<WeaponId, Model.Metadata.Weapon.Weapon> idWeaponMap = await metadataService.GetIdToWeaponMapAsync(token).ConfigureAwait(false);
|
|
||||||
|
|
||||||
Dictionary<string, Model.Metadata.Avatar.Avatar> nameAvatarMap = await metadataService.GetNameToAvatarMapAsync(token).ConfigureAwait(false);
|
|
||||||
Dictionary<string, Model.Metadata.Weapon.Weapon> nameWeaponMap = await metadataService.GetNameToWeaponMapAsync(token).ConfigureAwait(false);
|
|
||||||
context = new(idAvatarMap, idWeaponMap, nameAvatarMap, nameWeaponMap);
|
|
||||||
|
|
||||||
ArchiveCollection = gachaLogDbService.GetGachaArchiveCollection();
|
ArchiveCollection = gachaLogDbService.GetGachaArchiveCollection();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,12 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Snap.Hutao.Model;
|
using Snap.Hutao.Model;
|
||||||
|
using Snap.Hutao.Model.Metadata;
|
||||||
using Snap.Hutao.Model.Metadata.Abstraction;
|
using Snap.Hutao.Model.Metadata.Abstraction;
|
||||||
using Snap.Hutao.Model.Metadata.Avatar;
|
using Snap.Hutao.Model.Metadata.Avatar;
|
||||||
using Snap.Hutao.Model.Metadata.Weapon;
|
using Snap.Hutao.Model.Metadata.Weapon;
|
||||||
using Snap.Hutao.Model.Primitive;
|
using Snap.Hutao.Model.Primitive;
|
||||||
|
using Snap.Hutao.Service.Metadata.ContextAbstraction;
|
||||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||||
|
|
||||||
namespace Snap.Hutao.Service.GachaLog;
|
namespace Snap.Hutao.Service.GachaLog;
|
||||||
@@ -13,65 +15,28 @@ namespace Snap.Hutao.Service.GachaLog;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 祈愿记录服务上下文
|
/// 祈愿记录服务上下文
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal readonly struct GachaLogServiceMetadataContext
|
internal sealed class GachaLogServiceMetadataContext : IMetadataContext,
|
||||||
|
IMetadataSupportInitialization,
|
||||||
|
IMetadataListGachaEventSource,
|
||||||
|
IMetadataDictionaryIdAvatarSource,
|
||||||
|
IMetadataDictionaryIdWeaponSource,
|
||||||
|
IMetadataDictionaryNameAvatarSource,
|
||||||
|
IMetadataDictionaryNameWeaponSource
|
||||||
{
|
{
|
||||||
/// <summary>
|
public Dictionary<string, Item> ItemCache { get; set; } = [];
|
||||||
/// 物品缓存
|
|
||||||
/// </summary>
|
|
||||||
public readonly Dictionary<string, Item> ItemCache = [];
|
|
||||||
|
|
||||||
/// <summary>
|
public List<GachaEvent> GachaEvents { get; set; } = default!;
|
||||||
/// Id 角色 映射
|
|
||||||
/// </summary>
|
|
||||||
public readonly Dictionary<AvatarId, Avatar> IdAvatarMap;
|
|
||||||
|
|
||||||
/// <summary>
|
public Dictionary<AvatarId, Avatar> IdAvatarMap { get; set; } = default!;
|
||||||
/// Id 武器 映射
|
|
||||||
/// </summary>
|
|
||||||
public readonly Dictionary<WeaponId, Weapon> IdWeaponMap;
|
|
||||||
|
|
||||||
/// <summary>
|
public Dictionary<WeaponId, Weapon> IdWeaponMap { get; set; } = default!;
|
||||||
/// 名称 角色 映射
|
|
||||||
/// </summary>
|
|
||||||
public readonly Dictionary<string, Avatar> NameAvatarMap;
|
|
||||||
|
|
||||||
/// <summary>
|
public Dictionary<string, Avatar> NameAvatarMap { get; set; } = default!;
|
||||||
/// 名称 武器 映射
|
|
||||||
/// </summary>
|
|
||||||
public readonly Dictionary<string, Weapon> NameWeaponMap;
|
|
||||||
|
|
||||||
/// <summary>
|
public Dictionary<string, Weapon> NameWeaponMap { get; set; } = default!;
|
||||||
/// 是否初始化完成
|
|
||||||
/// </summary>
|
|
||||||
public readonly bool IsInitialized;
|
|
||||||
|
|
||||||
/// <summary>
|
public bool IsInitialized { get; set; }
|
||||||
/// 构造一个新的祈愿记录服务上下文
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="idAvatarMap">Id 角色 映射</param>
|
|
||||||
/// <param name="idWeaponMap">Id 武器 映射</param>
|
|
||||||
/// <param name="nameAvatarMap">名称 角色 映射</param>
|
|
||||||
/// <param name="nameWeaponMap">名称 武器 映射</param>
|
|
||||||
public GachaLogServiceMetadataContext(
|
|
||||||
Dictionary<AvatarId, Avatar> idAvatarMap,
|
|
||||||
Dictionary<WeaponId, Weapon> idWeaponMap,
|
|
||||||
Dictionary<string, Avatar> nameAvatarMap,
|
|
||||||
Dictionary<string, Weapon> nameWeaponMap)
|
|
||||||
{
|
|
||||||
IdAvatarMap = idAvatarMap;
|
|
||||||
IdWeaponMap = idWeaponMap;
|
|
||||||
NameAvatarMap = nameAvatarMap;
|
|
||||||
NameWeaponMap = nameWeaponMap;
|
|
||||||
|
|
||||||
IsInitialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 按名称获取物品
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="name">名称</param>
|
|
||||||
/// <param name="type">类型</param>
|
|
||||||
/// <returns>物品</returns>
|
|
||||||
public Item GetItemByNameAndType(string name, string type)
|
public Item GetItemByNameAndType(string name, string type)
|
||||||
{
|
{
|
||||||
if (!ItemCache.TryGetValue(name, out Item? result))
|
if (!ItemCache.TryGetValue(name, out Item? result))
|
||||||
@@ -93,11 +58,6 @@ internal readonly struct GachaLogServiceMetadataContext
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 按物品 Id 获取名称星级
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">Id</param>
|
|
||||||
/// <returns>名称星级</returns>
|
|
||||||
public INameQuality GetNameQualityByItemId(uint id)
|
public INameQuality GetNameQualityByItemId(uint id)
|
||||||
{
|
{
|
||||||
uint place = id.StringLength();
|
uint place = id.StringLength();
|
||||||
@@ -109,12 +69,6 @@ internal readonly struct GachaLogServiceMetadataContext
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取物品 Id
|
|
||||||
/// O(1)
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="item">祈愿物品</param>
|
|
||||||
/// <returns>物品 Id</returns>
|
|
||||||
public uint GetItemId(GachaLogItem item)
|
public uint GetItemId(GachaLogItem item)
|
||||||
{
|
{
|
||||||
if (item.ItemType == SH.ModelInterchangeUIGFItemTypeAvatar)
|
if (item.ItemType == SH.ModelInterchangeUIGFItemTypeAvatar)
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ internal interface IGachaLogHutaoCloudService
|
|||||||
/// <param name="uid">uid</param>
|
/// <param name="uid">uid</param>
|
||||||
/// <param name="token">取消令牌</param>
|
/// <param name="token">取消令牌</param>
|
||||||
/// <returns>是否获取成功</returns>
|
/// <returns>是否获取成功</returns>
|
||||||
ValueTask<ValueResult<bool, Guid>> RetrieveGachaItemsAsync(string uid, CancellationToken token = default);
|
ValueTask<ValueResult<bool, Guid>> RetrieveGachaArchiveIdAsync(string uid, CancellationToken token = default);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步上传祈愿记录
|
/// 异步上传祈愿记录
|
||||||
|
|||||||
@@ -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<string, Model.Metadata.Avatar.Avatar> NameAvatarMap { get; set; }
|
||||||
|
}
|
||||||
@@ -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<string, Model.Metadata.Weapon.Weapon> NameWeaponMap { get; set; }
|
||||||
|
}
|
||||||
@@ -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; }
|
||||||
|
}
|
||||||
@@ -30,27 +30,42 @@ internal static class MetadataServiceContextExtension
|
|||||||
|
|
||||||
// Dictionary
|
// 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;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma warning disable SH002
|
#pragma warning disable SH002
|
||||||
public static IEnumerable<Material> EnumerateInventroyMaterial(this IMetadataListMaterialSource context)
|
public static IEnumerable<Material> EnumerateInventoryMaterial(this IMetadataListMaterialSource context)
|
||||||
{
|
{
|
||||||
return context.Materials.Where(m => m.IsInventoryItem()).OrderBy(m => m.Id.Value);
|
return context.Materials.Where(m => m.IsInventoryItem()).OrderBy(m => m.Id.Value);
|
||||||
}
|
}
|
||||||
@@ -60,6 +75,11 @@ internal static class MetadataServiceContextExtension
|
|||||||
return context.IdAvatarMap[id];
|
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)
|
public static Material GetMaterial(this IMetadataDictionaryIdMaterialSource context, MaterialId id)
|
||||||
{
|
{
|
||||||
return context.IdMaterialMap[id];
|
return context.IdMaterialMap[id];
|
||||||
@@ -69,5 +89,10 @@ internal static class MetadataServiceContextExtension
|
|||||||
{
|
{
|
||||||
return context.IdWeaponMap[id];
|
return context.IdWeaponMap[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Weapon GetWeapon(this IMetadataDictionaryNameWeaponSource context, string name)
|
||||||
|
{
|
||||||
|
return context.NameWeaponMap[name];
|
||||||
|
}
|
||||||
#pragma warning restore SH002
|
#pragma warning restore SH002
|
||||||
}
|
}
|
||||||
@@ -60,7 +60,7 @@ internal sealed partial class HutaoCloudViewModel : Abstraction.ViewModel
|
|||||||
|
|
||||||
using (await dialog.BlockAsync(taskContext).ConfigureAwait(false))
|
using (await dialog.BlockAsync(taskContext).ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
return await hutaoCloudService.RetrieveGachaItemsAsync(uid).ConfigureAwait(false);
|
return await hutaoCloudService.RetrieveGachaArchiveIdAsync(uid).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,12 @@ internal sealed class EndIds
|
|||||||
[JsonPropertyName("302")]
|
[JsonPropertyName("302")]
|
||||||
public long WeaponEventWish { get; set; }
|
public long WeaponEventWish { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 集录祈愿
|
||||||
|
/// </summary>
|
||||||
|
[JsonPropertyName("500")]
|
||||||
|
public long ChronicledWish { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取 Last Id
|
/// 获取 Last Id
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -83,5 +89,6 @@ internal sealed class EndIds
|
|||||||
yield return new(GachaType.Standard, StandardWish);
|
yield return new(GachaType.Standard, StandardWish);
|
||||||
yield return new(GachaType.ActivityAvatar, AvatarEventWish);
|
yield return new(GachaType.ActivityAvatar, AvatarEventWish);
|
||||||
yield return new(GachaType.ActivityWeapon, WeaponEventWish);
|
yield return new(GachaType.ActivityWeapon, WeaponEventWish);
|
||||||
|
yield return new(GachaType.ActivityCity, ChronicledWish);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,6 +10,11 @@ internal sealed class GachaEntry
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string Uid { get; set; } = default!;
|
public string Uid { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否被排除出了全球统计
|
||||||
|
/// </summary>
|
||||||
|
public bool Excluded { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 物品个数
|
/// 物品个数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
Reference in New Issue
Block a user