[skip ci] uigf 4 support part 3

This commit is contained in:
DismissedLight
2024-07-13 22:56:55 +08:00
parent 71e0452c6e
commit e98bee8a9b
12 changed files with 195 additions and 106 deletions

View File

@@ -9,7 +9,7 @@ namespace Snap.Hutao.Extension;
internal static class CollectionExtension
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsNullOrEmpty<TSource>([NotNullWhen(false)][MaybeNullWhen(true)] this Collection<TSource>? source)
public static bool IsNullOrEmpty<TSource>([NotNullWhen(false)][MaybeNullWhen(true)] this ICollection<TSource>? source)
{
if (source is { Count: > 0 })
{

View File

@@ -67,17 +67,6 @@ internal static class ListExtension
return list.GetRange(start, length);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsNullOrEmpty<TSource>([NotNullWhen(false)][MaybeNullWhen(true)] this List<TSource>? source)
{
if (source is { Count: > 0 })
{
return false;
}
return true;
}
public static void RemoveLast<T>(this IList<T> collection)
{
collection.RemoveAt(collection.Count - 1);

View File

@@ -8,11 +8,17 @@ namespace Snap.Hutao.Model.Entity.Abstraction;
internal interface IDbMappingForeignKeyFrom<TSource, TFrom>
{
[Pure]
static abstract TSource From(in Guid foreignKey, in TFrom from);
static abstract TSource From(Guid foreignKey, TFrom from);
}
internal interface IDbMappingForeignKeyFrom<TSource, T1, T2>
{
[Pure]
static abstract TSource From(in Guid foreignKey, in T1 param1, in T2 param2);
static abstract TSource From(Guid foreignKey, T1 param1, T2 param2);
}
internal interface IDbMappingForeignKeyFrom<TSource, T1, T2, T3>
{
[Pure]
static abstract TSource From(Guid foreignKey, T1 param1, T2 param2, T3 param3);
}

View File

@@ -2,6 +2,7 @@
// Licensed under the MIT license.
using Snap.Hutao.Model.Entity.Abstraction;
using Snap.Hutao.Model.InterChange;
using Snap.Hutao.Model.InterChange.Achievement;
using Snap.Hutao.Model.Intrinsic;
using Snap.Hutao.Model.Primitive;
@@ -14,7 +15,8 @@ namespace Snap.Hutao.Model.Entity;
internal sealed class Achievement : IAppDbEntityHasArchive,
IEquatable<Achievement>,
IDbMappingForeignKeyFrom<Achievement, AchievementId>,
IDbMappingForeignKeyFrom<Achievement, UIAFItem>
IDbMappingForeignKeyFrom<Achievement, UIAFItem>,
IDbMappingForeignKeyFrom<Achievement, HutaoReservedAchievement>
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
@@ -33,7 +35,7 @@ internal sealed class Achievement : IAppDbEntityHasArchive,
public AchievementStatus Status { get; set; }
public static Achievement From(in Guid archiveId, in AchievementId id)
public static Achievement From(Guid archiveId, AchievementId id)
{
return new()
{
@@ -44,11 +46,11 @@ internal sealed class Achievement : IAppDbEntityHasArchive,
};
}
public static Achievement From(in Guid userId, in UIAFItem uiaf)
public static Achievement From(Guid archiveId, UIAFItem uiaf)
{
return new()
{
ArchiveId = userId,
ArchiveId = archiveId,
Id = uiaf.Id,
Current = uiaf.Current,
Status = uiaf.Status,
@@ -56,6 +58,18 @@ internal sealed class Achievement : IAppDbEntityHasArchive,
};
}
public static Achievement From(Guid archiveId, HutaoReservedAchievement achievement)
{
return new()
{
ArchiveId = archiveId,
Id = achievement.Id,
Current = achievement.Current,
Status = achievement.Status,
Time = achievement.Time,
};
}
public bool Equals(Achievement? other)
{
if (other is null)

View File

@@ -2,6 +2,7 @@
// Licensed under the MIT license.
using Snap.Hutao.Model.Entity.Abstraction;
using Snap.Hutao.Model.InterChange;
using Snap.Hutao.Model.InterChange.GachaLog;
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
using System.ComponentModel.DataAnnotations;
@@ -10,70 +11,34 @@ using System.Globalization;
namespace Snap.Hutao.Model.Entity;
/// <summary>
/// 抽卡记录物品
/// </summary>
[HighQuality]
[Table("gacha_items")]
internal sealed partial class GachaItem
: IDbMappingForeignKeyFrom<GachaItem, GachaLogItem, uint>,
IDbMappingForeignKeyFrom<GachaItem, LegacyUIGFItem, uint>,
IDbMappingForeignKeyFrom<GachaItem, LegacyUIGFItem>,
IDbMappingForeignKeyFrom<GachaItem, Web.Hutao.GachaLog.GachaItem>
IDbMappingForeignKeyFrom<GachaItem, Web.Hutao.GachaLog.GachaItem>,
IDbMappingForeignKeyFrom<GachaItem, Hk4eItem, int>
{
/// <summary>
/// 内部Id
/// </summary>
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid InnerId { get; set; }
/// <summary>
/// 存档
/// </summary>
[ForeignKey(nameof(ArchiveId))]
public GachaArchive Archive { get; set; } = default!;
/// <summary>
/// 存档Id
/// </summary>
public Guid ArchiveId { get; set; }
/// <summary>
/// 祈愿记录分类
/// </summary>
public GachaType GachaType { get; set; }
/// <summary>
/// 祈愿记录查询分类
/// 合并保底的卡池使用此属性
/// 仅4种不含400
/// </summary>
public GachaType QueryType { get; set; }
/// <summary>
/// 物品Id
/// </summary>
public uint ItemId { get; set; }
/// <summary>
/// 获取时间
/// </summary>
public DateTimeOffset Time { get; set; }
/// <summary>
/// 物品
/// </summary>
public long Id { get; set; }
/// <summary>
/// 构造一个新的数据库祈愿物品
/// </summary>
/// <param name="archiveId">存档Id</param>
/// <param name="item">祈愿物品</param>
/// <param name="itemId">物品Id</param>
/// <returns>新的祈愿物品</returns>
public static GachaItem From(in Guid archiveId, in GachaLogItem item, in uint itemId)
public static GachaItem From(Guid archiveId, GachaLogItem item, uint itemId)
{
return new()
{
@@ -86,14 +51,7 @@ internal sealed partial class GachaItem
};
}
/// <summary>
/// 构造一个新的数据库祈愿物品
/// </summary>
/// <param name="archiveId">存档Id</param>
/// <param name="item">祈愿物品</param>
/// <param name="itemId">物品Id</param>
/// <returns>新的祈愿物品</returns>
public static GachaItem From(in Guid archiveId, in LegacyUIGFItem item, in uint itemId)
public static GachaItem From(Guid archiveId, LegacyUIGFItem item, uint itemId)
{
return new()
{
@@ -106,13 +64,7 @@ internal sealed partial class GachaItem
};
}
/// <summary>
/// 构造一个新的数据库祈愿物品
/// </summary>
/// <param name="archiveId">存档Id</param>
/// <param name="item">祈愿物品</param>
/// <returns>新的祈愿物品</returns>
public static GachaItem From(in Guid archiveId, in LegacyUIGFItem item)
public static GachaItem From(Guid archiveId, LegacyUIGFItem item)
{
return new()
{
@@ -125,13 +77,7 @@ internal sealed partial class GachaItem
};
}
/// <summary>
/// 构造一个新的数据库祈愿物品
/// </summary>
/// <param name="archiveId">存档Id</param>
/// <param name="item">祈愿物品</param>
/// <returns>新的祈愿物品</returns>
public static GachaItem From(in Guid archiveId, in Web.Hutao.GachaLog.GachaItem item)
public static GachaItem From(Guid archiveId, Web.Hutao.GachaLog.GachaItem item)
{
return new()
{
@@ -143,4 +89,17 @@ internal sealed partial class GachaItem
Id = item.Id,
};
}
public static GachaItem From(Guid archiveId, Hk4eItem item, int timezone)
{
return new()
{
ArchiveId = archiveId,
GachaType = item.GachaType,
QueryType = item.UIGFGachaType,
ItemId = item.ItemId,
Time = new(item.Time, new(timezone, 0, 0)),
Id = item.Id,
};
}
}

View File

@@ -83,4 +83,14 @@ internal sealed partial class AchievementDbService : IAchievementDbService
{
return this.SingleOrDefault<AchievementArchive>(a => a.InnerId == archiveId);
}
public AchievementArchive? GetAchievementArchiveByName(string name)
{
return this.SingleOrDefault<AchievementArchive>(a => a.Name == name);
}
public void AddAchievementArchive(AchievementArchive archive)
{
this.Add(archive);
}
}

View File

@@ -11,12 +11,16 @@ namespace Snap.Hutao.Service.Achievement;
internal interface IAchievementDbService : IAppDbService<EntityArchive>, IAppDbService<EntityAchievement>
{
void AddAchievementArchive(EntityArchive archive);
ObservableCollection<EntityArchive> GetAchievementArchiveCollection();
List<EntityArchive> GetAchievementArchiveList();
EntityArchive? GetAchievementArchiveById(Guid archiveId);
EntityArchive? GetAchievementArchiveByName(string name);
void RemoveAchievementArchive(EntityArchive archive);
List<EntityAchievement> GetAchievementListByArchiveId(Guid archiveId);

View File

@@ -0,0 +1,9 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Service.UIGF;
internal interface IUIGFImportService
{
ValueTask<bool> ImportAsync(UIGFImportOptions importOptions, CancellationToken token);
}

View File

@@ -218,20 +218,3 @@ internal sealed partial class UIGF40ExportService : IUIGFExportService
hutaoReserved.SpiralAbyss = results;
}
}
[ConstructorGenerated]
[Injection(InjectAs.Transient, typeof(IUIGFImportService), Key = UIGFVersion.UIGF40)]
internal sealed partial class UIGF40ImportService : IUIGFImportService
{
public async ValueTask<bool> ImportAsync(UIGFImportOptions importOptions, CancellationToken token)
{
await Task.CompletedTask;
return true;
}
}
internal interface IUIGFImportService
{
}

View File

@@ -0,0 +1,105 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Core;
using Snap.Hutao.Model.Entity;
using Snap.Hutao.Model.InterChange;
using Snap.Hutao.Service.Achievement;
using Snap.Hutao.Service.GachaLog;
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
namespace Snap.Hutao.Service.UIGF;
[ConstructorGenerated]
[Injection(InjectAs.Transient, typeof(IUIGFImportService), Key = UIGFVersion.UIGF40)]
internal sealed partial class UIGF40ImportService : IUIGFImportService
{
private readonly JsonSerializerOptions jsonOptions;
private readonly IServiceProvider serviceProvider;
private readonly RuntimeOptions runtimeOptions;
private readonly ITaskContext taskContext;
public async ValueTask<bool> ImportAsync(UIGFImportOptions importOptions, CancellationToken token)
{
await taskContext.SwitchToBackgroundAsync();
ImportGachaArchives(importOptions.UIGF.Hk4e, importOptions.GachaArchiveUids);
ImportAchievementArchives(importOptions.UIGF.HutaoReserved?.Achievement, importOptions.ReservedAchievementArchiveIdentities);
return true;
}
private void ImportGachaArchives(List<UIGFEntry<Hk4eItem>>? entries, HashSet<string> uids)
{
if (entries.IsNullOrEmpty() || uids.IsNullOrEmpty())
{
return;
}
IGachaLogDbService gachaLogDbService = serviceProvider.GetRequiredService<IGachaLogDbService>();
foreach (UIGFEntry<Hk4eItem> entry in entries)
{
if (!uids.Contains(entry.Uid))
{
continue;
}
GachaArchive? archive = gachaLogDbService.GetGachaArchiveByUid(entry.Uid);
if (archive is null)
{
archive = GachaArchive.From(entry.Uid);
gachaLogDbService.AddGachaArchive(archive);
}
Guid archiveId = archive.InnerId;
List<GachaItem> fullItems = [];
foreach (GachaType queryType in GachaLog.GachaLog.QueryTypes)
{
long trimId = gachaLogDbService.GetOldestGachaItemIdByArchiveIdAndQueryType(archiveId, queryType);
List<GachaItem> currentTypedList = entry.List
.Where(item => item.UIGFGachaType == queryType && item.Id > trimId)
.OrderByDescending(item => item.Id)
.Select(item => GachaItem.From(archiveId, item, entry.TimeZone))
.ToList();
fullItems.AddRange(currentTypedList);
}
gachaLogDbService.AddGachaItemRange(fullItems);
}
}
private void ImportAchievementArchives(List<HutaoReservedEntry<HutaoReservedAchievement>>? entries, HashSet<string> identities)
{
if (entries.IsNullOrEmpty() || identities.IsNullOrEmpty())
{
return;
}
IAchievementDbService achievementDbService = serviceProvider.GetRequiredService<IAchievementDbService>();
AchievementDbBulkOperation achievementDbBulkOperation = serviceProvider.GetRequiredService<AchievementDbBulkOperation>();
foreach (HutaoReservedEntry<HutaoReservedAchievement> entry in entries)
{
if (!identities.Contains(entry.Identity))
{
continue;
}
AchievementArchive? archive = achievementDbService.GetAchievementArchiveByName(entry.Identity);
if (archive is null)
{
archive = AchievementArchive.From(entry.Identity);
achievementDbService.AddAchievementArchive(archive);
}
Guid archiveId = archive.InnerId;
List<Model.Entity.Achievement> achievements = entry.List.SelectList(item => Model.Entity.Achievement.From(archiveId, item));
achievementDbBulkOperation.Overwrite(archiveId, achievements);
}
}
}

View File

@@ -9,20 +9,11 @@ internal sealed class UIGFExportOptions
public required List<Guid> GachaArchiveIds { get; set; }
public required List<Guid> ReservedAchievementArchiveIds { get; set; }
public required List<Guid> ReservedAchievementArchiveIds { get; set; }
public required List<string> ReservedAvatarInfoUids { get; set; }
public required List<Guid> ReservedCultivationProjectIds { get; set; }
public required List<string> ReservedSpiralAbyssUids { get; set; }
}
internal sealed class UIGFImportOptions
{
public Model.InterChange.UIGF UIGF { get; set; } = default!;
public HashSet<string> GachaArchiveUids { get; set; } = default!;
public HashSet<string> ReservedAchievementArchiveIdentities { get; set; } = default!;
}

View File

@@ -0,0 +1,19 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Service.UIGF;
internal sealed class UIGFImportOptions
{
public required Model.InterChange.UIGF UIGF { get; set; }
public required HashSet<string> GachaArchiveUids { get; set; }
public required HashSet<string> ReservedAchievementArchiveIdentities { get; set; }
public required HashSet<string> ReservedAvatarInfoIdentities { get; set; }
public required HashSet<string> ReservedCultivationProjectIdentities { get; set; }
public required HashSet<string> ReservedSpiralAbyssIdentities { get; set; }
}