fully support UIGF v2.3

This commit is contained in:
Lightczx
2023-05-15 12:37:46 +08:00
parent 5fe38f305b
commit ca10afa25a
13 changed files with 136 additions and 46 deletions

View File

@@ -1,4 +1,5 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Snap.Hutao.Test;
@@ -11,6 +12,12 @@ public class JsonSerializeTest
}
""";
private const string SmapleNumberObjectJson = """
{
"A" : ""
}
""";
[TestMethod]
public void DelegatePropertyCanSerialize()
{
@@ -18,9 +25,23 @@ public class JsonSerializeTest
Assert.AreEqual(sample.B, 1);
}
[TestMethod]
public void EmptyStringCanSerializeAsNumber()
{
// Throw
StringNumberSample sample = JsonSerializer.Deserialize<StringNumberSample>(SmapleNumberObjectJson)!;
Assert.AreEqual(sample.A, 0);
}
private class Sample
{
public int A { get => B; set => B = value; }
public int B { get; set; }
}
private class StringNumberSample
{
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)]
public int A { get; set; }
}
}

View File

@@ -103,7 +103,7 @@ internal sealed class GachaItem
/// <param name="item">祈愿物品</param>
/// <param name="itemId">物品Id</param>
/// <returns>新的祈愿物品</returns>
public static GachaItem Create(in Guid archiveId, UIGFItem item, int itemId)
public static GachaItem CreateForMajor2Minor2OrLower(in Guid archiveId, UIGFItem item, int itemId)
{
return new()
{
@@ -116,6 +116,25 @@ internal sealed class GachaItem
};
}
/// <summary>
/// 构造一个新的数据库祈愿物品
/// </summary>
/// <param name="archiveId">存档Id</param>
/// <param name="item">祈愿物品</param>
/// <returns>新的祈愿物品</returns>
public static GachaItem CreateForMajor2Minor3OrHigher(in Guid archiveId, UIGFItem item)
{
return new()
{
ArchiveId = archiveId,
GachaType = item.GachaType,
QueryType = item.UIGFGachaType,
ItemId = int.Parse(item.ItemId),
Time = item.Time,
Id = item.Id,
};
}
/// <summary>
/// 构造一个新的数据库祈愿物品
/// </summary>
@@ -159,6 +178,7 @@ internal sealed class GachaItem
return new()
{
GachaType = GachaType,
ItemId = $"{ItemId}",
Count = 1,
Time = Time,
Name = nameQuality.Name,

View File

@@ -1,8 +1,6 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using System.Collections.Immutable;
namespace Snap.Hutao.Model.InterChange.GachaLog;
/// <summary>
@@ -13,14 +11,9 @@ namespace Snap.Hutao.Model.InterChange.GachaLog;
internal sealed class UIGF
{
/// <summary>
/// 当前发行的版本
/// 当前版本
/// </summary>
public const string CurrentVersion = "v2.2";
private static readonly ImmutableList<string> SupportedVersion = new List<string>()
{
"v2.1", CurrentVersion,
}.ToImmutableList();
public const string CurrentVersion = "v2.3";
/// <summary>
/// 信息
@@ -37,17 +30,26 @@ internal sealed class UIGF
/// <summary>
/// 确认当前UIGF对象的版本是否受支持
/// </summary>
/// <param name="version">版本</param>
/// <returns>当前UIAF对象是否受支持</returns>
public bool IsCurrentVersionSupported()
public bool IsCurrentVersionSupported(out UIGFVersion version)
{
return SupportedVersion.Contains(Info?.UIGFVersion ?? string.Empty);
version = Info.UIGFVersion switch
{
"v2.1" => UIGFVersion.Major2Minor2OrLower,
"v2.2" => UIGFVersion.Major2Minor2OrLower,
"v2.3" => UIGFVersion.Major2Minor3OrHigher,
_ => UIGFVersion.NotSupported,
};
return version != UIGFVersion.NotSupported;
}
/// <summary>
/// 列表物品是否正常
/// </summary>
/// <returns>是否正常</returns>
public bool IsValidList()
public bool IsMajor2Minor2OrLowerListValid()
{
foreach (UIGFItem item in List)
{

View File

@@ -0,0 +1,25 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
namespace Snap.Hutao.Model.InterChange.GachaLog;
/// <summary>
/// UIGF版本
/// </summary>
internal enum UIGFVersion
{
/// <summary>
/// 不支持的版本
/// </summary>
NotSupported,
/// <summary>
/// v2.2以及之前的版本
/// </summary>
Major2Minor2OrLower,
/// <summary>
/// v2.3以及之后的版本
/// </summary>
Major2Minor3OrHigher,
}

View File

@@ -28,8 +28,8 @@ internal sealed partial class GachaLogService : IGachaLogService
private readonly ScopedDbCurrent<GachaArchive, Message.GachaArchiveChangedMessage> dbCurrent;
private readonly IGachaStatisticsSlimFactory gachaStatisticsSlimFactory;
private readonly IGachaStatisticsFactory gachaStatisticsFactory;
private readonly IGachaLogExportService gachaLogExportService;
private readonly IGachaLogImportService gachaLogImportService;
private readonly IUIGFExportService gachaLogExportService;
private readonly IUIGFImportService gachaLogImportService;
private readonly IServiceProvider serviceProvider;
private readonly IMetadataService metadataService;
private readonly ILogger<GachaLogService> logger;
@@ -134,13 +134,13 @@ internal sealed partial class GachaLogService : IGachaLogService
/// <inheritdoc/>
public Task<UIGF> ExportToUIGFAsync(GachaArchive archive)
{
return gachaLogExportService.ExportToUIGFAsync(context, archive);
return gachaLogExportService.ExportAsync(context, archive);
}
/// <inheritdoc/>
public async Task ImportFromUIGFAsync(List<UIGFItem> list, string uid)
public async Task ImportFromUIGFAsync(UIGF uigf)
{
CurrentArchive = await gachaLogImportService.ImportFromUIGFAsync(context, list, uid).ConfigureAwait(false);
CurrentArchive = await gachaLogImportService.ImportAsync(context, uigf).ConfigureAwait(false);
}
/// <inheritdoc/>

View File

@@ -48,10 +48,9 @@ internal interface IGachaLogService
/// <summary>
/// 异步从UIGF导入数据
/// </summary>
/// <param name="list">列表</param>
/// <param name="uid">Uid</param>
/// <param name="uigf">信息</param>
/// <returns>任务</returns>
Task ImportFromUIGFAsync(List<UIGFItem> list, string uid);
Task ImportFromUIGFAsync(UIGF uigf);
/// <summary>
/// 异步初始化

View File

@@ -9,7 +9,7 @@ namespace Snap.Hutao.Service.GachaLog;
/// <summary>
/// 祈愿记录导出服务
/// </summary>
internal interface IGachaLogExportService
internal interface IUIGFExportService
{
/// <summary>
/// 异步导出存档到 UIGF
@@ -17,5 +17,5 @@ internal interface IGachaLogExportService
/// <param name="context">元数据上下文</param>
/// <param name="archive">存档</param>
/// <returns>UIGF</returns>
Task<UIGF> ExportToUIGFAsync(GachaLogServiceContext context, GachaArchive archive);
Task<UIGF> ExportAsync(GachaLogServiceContext context, GachaArchive archive);
}

View File

@@ -9,14 +9,13 @@ namespace Snap.Hutao.Service.GachaLog;
/// <summary>
/// 祈愿记录导入服务
/// </summary>
internal interface IGachaLogImportService
internal interface IUIGFImportService
{
/// <summary>
/// 异步从 UIGF 导入
/// </summary>
/// <param name="context">祈愿记录服务上下文</param>
/// <param name="list">列表</param>
/// <param name="uid">uid</param>
/// <param name="uigf">数据</param>
/// <returns>存档</returns>
Task<GachaArchive> ImportFromUIGFAsync(GachaLogServiceContext context, List<UIGFItem> list, string uid);
Task<GachaArchive> ImportAsync(GachaLogServiceContext context, UIGF uigf);
}

View File

@@ -11,14 +11,14 @@ namespace Snap.Hutao.Service.GachaLog;
/// 祈愿记录导出服务
/// </summary>
[ConstructorGenerated]
[Injection(InjectAs.Scoped, typeof(IGachaLogExportService))]
internal sealed partial class GachaLogExportService : IGachaLogExportService
[Injection(InjectAs.Scoped, typeof(IUIGFExportService))]
internal sealed partial class UIGFExportService : IUIGFExportService
{
private readonly IServiceProvider serviceProvider;
private readonly ITaskContext taskContext;
/// <inheritdoc/>
public async Task<UIGF> ExportToUIGFAsync(GachaLogServiceContext context, GachaArchive archive)
public async Task<UIGF> ExportAsync(GachaLogServiceContext context, GachaArchive archive)
{
await taskContext.SwitchToBackgroundAsync();
using (IServiceScope scope = serviceProvider.CreateScope())

View File

@@ -9,25 +9,25 @@ using Snap.Hutao.Model.InterChange.GachaLog;
namespace Snap.Hutao.Service.GachaLog;
/// <summary>
/// 祈愿记录导入服务
/// v2.1 v2.2 祈愿记录导入服务
/// </summary>
[ConstructorGenerated]
[Injection(InjectAs.Scoped, typeof(IGachaLogImportService))]
internal sealed partial class GachaLogImportService : IGachaLogImportService
[Injection(InjectAs.Scoped, typeof(IUIGFImportService))]
internal sealed partial class UIGFImportService : IUIGFImportService
{
private readonly ILogger<GachaLogImportService> logger;
private readonly ILogger<UIGFImportService> logger;
private readonly IServiceProvider serviceProvider;
private readonly ITaskContext taskContext;
/// <inheritdoc/>
public async Task<GachaArchive> ImportFromUIGFAsync(GachaLogServiceContext context, List<UIGFItem> list, string uid)
public async Task<GachaArchive> ImportAsync(GachaLogServiceContext context, UIGF uigf)
{
await taskContext.SwitchToBackgroundAsync();
using (IServiceScope scope = serviceProvider.CreateScope())
{
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
GachaArchiveInitializationContext initContext = new(taskContext, uid, appDbContext.GachaArchives, context.ArchiveCollection);
GachaArchiveInitializationContext initContext = new(taskContext, uigf.Info.Uid, appDbContext.GachaArchives, context.ArchiveCollection);
GachaArchive.Init(initContext, out GachaArchive? archive);
Guid archiveId = archive.InnerId;
@@ -38,10 +38,20 @@ internal sealed partial class GachaLogImportService : IGachaLogImportService
logger.LogInformation("Last Id to trim with: [{id}]", trimId);
IEnumerable<GachaItem> toAdd = list
.OrderByDescending(i => i.Id)
.Where(i => i.Id < trimId)
.Select(i => GachaItem.Create(archiveId, i, context.GetItemId(i)));
_ = uigf.IsCurrentVersionSupported(out UIGFVersion version);
IEnumerable<GachaItem> toAdd = version switch
{
UIGFVersion.Major2Minor3OrHigher => uigf.List
.OrderByDescending(i => i.Id)
.Where(i => i.Id < trimId)
.Select(i => GachaItem.CreateForMajor2Minor3OrHigher(archiveId, i)),
UIGFVersion.Major2Minor2OrLower => uigf.List
.OrderByDescending(i => i.Id)
.Where(i => i.Id < trimId)
.Select(i => GachaItem.CreateForMajor2Minor2OrLower(archiveId, i, context.GetItemId(i))),
_ => Enumerable.Empty<GachaItem>(),
};
await appDbContext.GachaItems.AddRangeAndSaveAsync(toAdd).ConfigureAwait(false);
return archive;

View File

@@ -100,7 +100,7 @@ internal static class ProcessInterop
HINSTANCE hKernelDll = GetModuleHandle("kernel32.dll");
Marshal.ThrowExceptionForHR(Marshal.GetLastPInvokeError());
FARPROC pLoadLibraryA = GetProcAddress(hKernelDll, libraryPathu8);
FARPROC pLoadLibraryA = GetProcAddress(hKernelDll, "LoadLibraryA"u8);
Marshal.ThrowExceptionForHR(Marshal.GetLastPInvokeError());
void* pNativeLibraryPath = default;

View File

@@ -104,6 +104,20 @@ internal sealed partial class GachaLogViewModel : Abstraction.ViewModel
}
}
private static bool CanImport(UIGFVersion version, UIGF uigf)
{
if (version == UIGFVersion.Major2Minor3OrHigher)
{
return true;
}
else if (version == UIGFVersion.Major2Minor2OrLower && uigf.IsMajor2Minor2OrLowerListValid())
{
return true;
}
return false;
}
[Command("RefreshByWebCacheCommand")]
private Task RefreshByWebCacheAsync()
{
@@ -331,19 +345,19 @@ internal sealed partial class GachaLogViewModel : Abstraction.ViewModel
private async Task<bool> TryImportUIGFInternalAsync(UIGF uigf)
{
if (uigf.IsCurrentVersionSupported())
if (uigf.IsCurrentVersionSupported(out UIGFVersion version))
{
// ContentDialog must be created by main thread.
await taskContext.SwitchToMainThreadAsync();
GachaLogImportDialog importDialog = serviceProvider.CreateInstance<GachaLogImportDialog>(uigf);
if (await importDialog.GetShouldImportAsync().ConfigureAwait(true))
{
if (uigf.IsValidList())
if (CanImport(version, uigf))
{
ContentDialog dialog = await contentDialogFactory.CreateForIndeterminateProgressAsync(SH.ViewModelGachaLogImportProgress).ConfigureAwait(true);
using (await dialog.BlockAsync(taskContext).ConfigureAwait(false))
{
await gachaLogService.ImportFromUIGFAsync(uigf.List, uigf.Info.Uid).ConfigureAwait(false);
await gachaLogService.ImportFromUIGFAsync(uigf).ConfigureAwait(false);
}
infoBarService.Success(SH.ViewModelGachaLogImportComplete);

View File

@@ -27,10 +27,10 @@ internal class GachaLogItem
/// <summary>
/// 总为 <see cref="string.Empty"/>
/// v2.3 使用了此值
/// </summary>
[Obsolete("API set this property empty")]
[JsonPropertyName("item_id")]
public string ItemId { get; set; } = string.Empty;
public string ItemId { get; set; } = default!;
/// <summary>
/// 个数 一般为 1