mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
add metadata service
This commit is contained in:
@@ -3,7 +3,8 @@
|
||||
<TargetFrameworks>net6.0-windows10.0.17763.0</TargetFrameworks>
|
||||
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
|
||||
<RootNamespace>SettingsUI</RootNamespace>
|
||||
<RuntimeIdentifiers>win10-x86;win10-x64;win10-arm64</RuntimeIdentifiers>
|
||||
<Platforms>x64</Platforms>
|
||||
<RuntimeIdentifiers>win10-x64</RuntimeIdentifiers>
|
||||
<UseWinUI>true</UseWinUI>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
@@ -107,7 +107,7 @@ internal static partial class ServiceCollectionExtensions
|
||||
lines.Add(lineBuilder.ToString());
|
||||
}
|
||||
|
||||
foreach (string line in lines.OrderByDescending(x => x))
|
||||
foreach (string line in lines.OrderBy(x => x))
|
||||
{
|
||||
sourceCodeBuilder.Append(line);
|
||||
}
|
||||
|
||||
@@ -54,8 +54,8 @@ Global
|
||||
{DCA5678C-896E-49FB-97A7-5A504A5CFF17}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DCA5678C-896E-49FB-97A7-5A504A5CFF17}.Debug|arm64.ActiveCfg = Debug|Any CPU
|
||||
{DCA5678C-896E-49FB-97A7-5A504A5CFF17}.Debug|arm64.Build.0 = Debug|Any CPU
|
||||
{DCA5678C-896E-49FB-97A7-5A504A5CFF17}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{DCA5678C-896E-49FB-97A7-5A504A5CFF17}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{DCA5678C-896E-49FB-97A7-5A504A5CFF17}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{DCA5678C-896E-49FB-97A7-5A504A5CFF17}.Debug|x64.Build.0 = Debug|x64
|
||||
{DCA5678C-896E-49FB-97A7-5A504A5CFF17}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{DCA5678C-896E-49FB-97A7-5A504A5CFF17}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{DCA5678C-896E-49FB-97A7-5A504A5CFF17}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
<StaticResource x:Key="WindowCaptionForeground" ResourceKey="SystemControlForegroundBaseHighBrush" />
|
||||
<StaticResource x:Key="WindowCaptionForegroundDisabled" ResourceKey="SystemControlForegroundBaseHighBrush" />
|
||||
|
||||
<StaticResource x:Key="ApplicationPageBackgroundThemeBrush" ResourceKey="ControlFillColorTransparentBrush" />
|
||||
|
||||
<Thickness x:Key="InfoBarIconMargin">6,16,16,16</Thickness>
|
||||
<Thickness x:Key="InfoBarContentRootPadding">16,0,0,0</Thickness>
|
||||
|
||||
|
||||
@@ -4,7 +4,11 @@
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.Windows.AppLifecycle;
|
||||
using Snap.Hutao.Core.Logging;
|
||||
using Snap.Hutao.Service.Abstraction;
|
||||
using System.Diagnostics;
|
||||
using Windows.ApplicationModel.Activation;
|
||||
|
||||
namespace Snap.Hutao;
|
||||
|
||||
@@ -14,10 +18,10 @@ namespace Snap.Hutao;
|
||||
public partial class App : Application
|
||||
{
|
||||
private static Window? window;
|
||||
private readonly ILogger<App> logger;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the singleton application object.
|
||||
/// This is the first line of authored code executed, and as such is the logical equivalent of main() or WinMain().
|
||||
/// </summary>
|
||||
public App()
|
||||
{
|
||||
@@ -25,6 +29,7 @@ public partial class App : Application
|
||||
InitializeComponent();
|
||||
InitializeDependencyInjection();
|
||||
|
||||
logger = Ioc.Default.GetRequiredService<ILogger<App>>();
|
||||
UnhandledException += AppUnhandledException;
|
||||
}
|
||||
|
||||
@@ -34,14 +39,38 @@ public partial class App : Application
|
||||
public static Window? Window { get => window; set => window = value; }
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when the application is launched normally by the end user.
|
||||
/// Other entry points will be used such as when the application is launched to open a specific file.
|
||||
/// Invoked when the application is launched.
|
||||
/// </summary>
|
||||
/// <param name="args">Details about the launch request and process.</param>
|
||||
protected override void OnLaunched(LaunchActivatedEventArgs args)
|
||||
[SuppressMessage("", "VSTHRD100")]
|
||||
protected override async void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
|
||||
{
|
||||
Window = Ioc.Default.GetRequiredService<MainWindow>();
|
||||
Window.Activate();
|
||||
AppActivationArguments activatedEventArgs = AppInstance.GetCurrent().GetActivatedEventArgs();
|
||||
AppInstance mainInstance = AppInstance.FindOrRegisterForKey("main");
|
||||
|
||||
if (!mainInstance.IsCurrent)
|
||||
{
|
||||
// Redirect the activation (and args) to the "main" instance, and exit.
|
||||
await mainInstance.RedirectActivationToAsync(activatedEventArgs);
|
||||
Process.GetCurrentProcess().Kill();
|
||||
}
|
||||
else
|
||||
{
|
||||
Uri? uri = null;
|
||||
if (activatedEventArgs.Kind == ExtendedActivationKind.Protocol)
|
||||
{
|
||||
IProtocolActivatedEventArgs protocolArgs = (activatedEventArgs.Data as IProtocolActivatedEventArgs)!;
|
||||
uri = protocolArgs.Uri;
|
||||
}
|
||||
|
||||
Window = Ioc.Default.GetRequiredService<MainWindow>();
|
||||
Window.Activate();
|
||||
|
||||
if (uri != null)
|
||||
{
|
||||
Ioc.Default.GetRequiredService<IInfoBarService>().Information(uri.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void InitializeDependencyInjection()
|
||||
@@ -56,7 +85,7 @@ public partial class App : Application
|
||||
.AddInjections()
|
||||
.AddDatebase()
|
||||
.AddHttpClients()
|
||||
.AddDefaultJsonSerializerOptions()
|
||||
.AddJsonSerializerOptions()
|
||||
|
||||
// Discrete services
|
||||
.AddSingleton<IMessenger>(WeakReferenceMessenger.Default)
|
||||
@@ -68,7 +97,6 @@ public partial class App : Application
|
||||
|
||||
private void AppUnhandledException(object sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e)
|
||||
{
|
||||
ILogger<App> logger = Ioc.Default.GetRequiredService<ILogger<App>>();
|
||||
logger.LogError(EventIds.UnhandledException, e.Exception, "未经处理的异常");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ public class AppDbContext : DbContext
|
||||
/// </summary>
|
||||
/// <param name="sqlConnectionString">连接字符串</param>
|
||||
/// <returns>应用程序数据库上下文</returns>
|
||||
public static AppDbContext CreateFrom(string sqlConnectionString)
|
||||
public static AppDbContext Create(string sqlConnectionString)
|
||||
{
|
||||
return new(new DbContextOptionsBuilder<AppDbContext>().UseSqlite(sqlConnectionString).Options);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,6 @@ public class AppDbContextDesignTimeFactory : IDesignTimeDbContextFactory<AppDbCo
|
||||
string dbFile = myDocument.Locate("Userdata.db");
|
||||
string sqlConnectionString = $"Data Source={dbFile}";
|
||||
|
||||
return AppDbContext.CreateFrom(sqlConnectionString);
|
||||
return AppDbContext.Create(sqlConnectionString);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,45 @@ internal abstract class FileSystemContext
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建文件,若已存在文件,则不会创建
|
||||
/// </summary>
|
||||
/// <param name="file">文件</param>
|
||||
public void CreateFileOrIgnore(string file)
|
||||
{
|
||||
file = Locate(file);
|
||||
if (!File.Exists(file))
|
||||
{
|
||||
File.Create(file).Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建文件夹,若已存在文件,则不会创建
|
||||
/// </summary>
|
||||
/// <param name="folder">文件夹</param>
|
||||
public void CreateFolderOrIgnore(string folder)
|
||||
{
|
||||
folder = Locate(folder);
|
||||
if (!Directory.Exists(folder))
|
||||
{
|
||||
Directory.CreateDirectory(folder);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 尝试删除文件夹
|
||||
/// </summary>
|
||||
/// <param name="folder">文件夹</param>
|
||||
public void DeleteFolderOrIgnore(string folder)
|
||||
{
|
||||
folder = Locate(folder);
|
||||
if (Directory.Exists(folder))
|
||||
{
|
||||
Directory.Delete(folder, true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查根目录
|
||||
/// </summary>
|
||||
@@ -113,41 +152,22 @@ internal abstract class FileSystemContext
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建文件,若已存在文件,则不会创建
|
||||
/// 等效于 <see cref="File.OpenRead(string)"/> ,但路径经过解析
|
||||
/// </summary>
|
||||
/// <param name="file">文件</param>
|
||||
public void CreateFileOrIgnore(string file)
|
||||
/// <param name="file">文件名</param>
|
||||
/// <returns>文件流</returns>
|
||||
public FileStream OpenRead(string file)
|
||||
{
|
||||
file = Locate(file);
|
||||
if (!File.Exists(file))
|
||||
{
|
||||
File.Create(file).Dispose();
|
||||
}
|
||||
return File.OpenRead(Locate(file));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建文件夹,若已存在文件,则不会创建
|
||||
/// 等效于 <see cref="File.Create(string)"/> ,但路径经过解析
|
||||
/// </summary>
|
||||
/// <param name="folder">文件夹</param>
|
||||
public void CreateFolderOrIgnore(string folder)
|
||||
/// <param name="file">文件名</param>
|
||||
/// <returns>文件流</returns>
|
||||
public FileStream Create(string file)
|
||||
{
|
||||
folder = Locate(folder);
|
||||
if (!Directory.Exists(folder))
|
||||
{
|
||||
Directory.CreateDirectory(folder);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 尝试删除文件夹
|
||||
/// </summary>
|
||||
/// <param name="folder">文件夹</param>
|
||||
public void DeleteFolderOrIgnore(string folder)
|
||||
{
|
||||
folder = Locate(folder);
|
||||
if (Directory.Exists(folder))
|
||||
{
|
||||
Directory.Delete(folder, true);
|
||||
}
|
||||
return File.Create(Locate(file));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.IO;
|
||||
|
||||
namespace Snap.Hutao.Context.FileSystem.Location;
|
||||
|
||||
/// <summary>
|
||||
/// 我的文档位置
|
||||
/// </summary>
|
||||
[Injection(InjectAs.Transient)]
|
||||
public class Metadata : IFileSystemLocation
|
||||
{
|
||||
private string? path;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string GetPath()
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
string myDocument = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
|
||||
path = Path.GetFullPath(Path.Combine(myDocument, "Hutao", "Metadata"));
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
}
|
||||
@@ -24,4 +24,4 @@ public class MyDocument : IFileSystemLocation
|
||||
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Context.FileSystem.Location;
|
||||
|
||||
namespace Snap.Hutao.Context.FileSystem;
|
||||
|
||||
/// <summary>
|
||||
/// 元数据上下文
|
||||
/// </summary>
|
||||
[Injection(InjectAs.Transient)]
|
||||
internal class MetadataContext : FileSystemContext
|
||||
{
|
||||
/// <inheritdoc cref="FileSystemContext"/>
|
||||
public MetadataContext(Metadata metadata)
|
||||
: base(metadata)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -17,9 +17,11 @@ public class CancellablePage : Page
|
||||
/// <summary>
|
||||
/// 初始化
|
||||
/// </summary>
|
||||
/// <param name="viewModel">视图模型</param>
|
||||
public void Initialize(ISupportCancellation viewModel)
|
||||
/// <typeparam name="TViewModel">视图模型类型</typeparam>
|
||||
public void InitializeWith<TViewModel>()
|
||||
where TViewModel : class, ISupportCancellation
|
||||
{
|
||||
ISupportCancellation viewModel = Ioc.Default.GetRequiredService<TViewModel>();
|
||||
viewModel.CancellationToken = viewLoadingConcellationTokenSource.Token;
|
||||
DataContext = viewModel;
|
||||
}
|
||||
|
||||
57
src/Snap.Hutao/Snap.Hutao/Control/Image/CachedImage.cs
Normal file
57
src/Snap.Hutao/Snap.Hutao/Control/Image/CachedImage.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using CommunityToolkit.WinUI.UI;
|
||||
using CommunityToolkit.WinUI.UI.Controls;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Microsoft.UI.Xaml.Media.Imaging;
|
||||
using Snap.Hutao.Extension;
|
||||
|
||||
namespace Snap.Hutao.Control.Image;
|
||||
|
||||
/// <summary>
|
||||
/// 缓存图像
|
||||
/// </summary>
|
||||
public class CachedImage : ImageEx
|
||||
{
|
||||
static CachedImage()
|
||||
{
|
||||
ImageCache.Instance.CacheDuration = Timeout.InfiniteTimeSpan;
|
||||
ImageCache.Instance.RetryCount = 3;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的缓存图像
|
||||
/// </summary>
|
||||
public CachedImage()
|
||||
{
|
||||
IsCacheEnabled = true;
|
||||
EnableLazyLoading = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override async Task<ImageSource> ProvideCachedResourceAsync(Uri imageUri, CancellationToken token)
|
||||
{
|
||||
BitmapImage image;
|
||||
try
|
||||
{
|
||||
image = await ImageCache.Instance.GetFromCacheAsync(imageUri, true, token);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// maybe the image is corrupted remove it and re-download
|
||||
await ImageCache.Instance.RemoveAsync(imageUri.Enumerate());
|
||||
image = await ImageCache.Instance.GetFromCacheAsync(imageUri, false, token);
|
||||
}
|
||||
|
||||
// check token state to determine whether the operation should be canceled.
|
||||
if (token.IsCancellationRequested)
|
||||
{
|
||||
throw new TaskCanceledException("Image source has changed.");
|
||||
}
|
||||
else
|
||||
{
|
||||
return Must.NotNull(image);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ internal interface ISupportAsyncInitialization
|
||||
/// <summary>
|
||||
/// 异步初始化
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">取消令牌</param>
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>初始化任务</returns>
|
||||
Task<bool> InitializeAsync(CancellationToken cancellationToken = default);
|
||||
ValueTask<bool> InitializeAsync(CancellationToken token = default);
|
||||
}
|
||||
@@ -5,6 +5,7 @@ namespace Snap.Hutao.Core.DependencyInjection.Annotation;
|
||||
|
||||
/// <summary>
|
||||
/// 指示被标注的类型可注入
|
||||
/// 由源生成器生成注入代码
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
|
||||
public class InjectionAttribute : Attribute
|
||||
@@ -15,27 +16,14 @@ public class InjectionAttribute : Attribute
|
||||
/// <param name="injectAs">指示注入方法</param>
|
||||
public InjectionAttribute(InjectAs injectAs)
|
||||
{
|
||||
InjectAs = injectAs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 指示该类将注入为带有接口实现的类
|
||||
/// </summary>
|
||||
/// <param name="injectAs">指示注入方法</param>
|
||||
/// <param name="impl">实现的接口类型</param>
|
||||
public InjectionAttribute(InjectAs injectAs, Type impl)
|
||||
/// <param name="interfaceType">实现的接口类型</param>
|
||||
public InjectionAttribute(InjectAs injectAs, Type interfaceType)
|
||||
{
|
||||
InterfaceType = impl;
|
||||
InjectAs = injectAs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注入类型
|
||||
/// </summary>
|
||||
public InjectAs InjectAs { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 该类实现的接口类型
|
||||
/// </summary>
|
||||
public Type? InterfaceType { get; }
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Snap.Hutao.Core.Json.Converter;
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Snap.Hutao.Core.Json.Converter;
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Snap.Hutao.Core.Json.Converter;
|
||||
|
||||
/// <summary>
|
||||
/// Json字典转换器
|
||||
/// </summary>
|
||||
/// <typeparam name="TKeyConverter">键的类型</typeparam>
|
||||
public class StringEnumKeyDictionaryConverter : JsonConverterFactory
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override bool CanConvert(Type typeToConvert)
|
||||
{
|
||||
if (!typeToConvert.IsGenericType)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeToConvert.GetGenericTypeDefinition() != typeof(Dictionary<,>))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return typeToConvert.GetGenericArguments()[0].IsEnum;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override JsonConverter CreateConverter(Type type, JsonSerializerOptions options)
|
||||
{
|
||||
Type keyType = type.GetGenericArguments()[0];
|
||||
Type valueType = type.GetGenericArguments()[1];
|
||||
|
||||
Type innerConverterType = typeof(StringEnumDictionaryConverterInner<,>).MakeGenericType(keyType, valueType);
|
||||
JsonConverter converter = (JsonConverter)Activator.CreateInstance(innerConverterType, BindingFlags.Instance | BindingFlags.Public, null, new object[] { options }, null)!;
|
||||
return converter;
|
||||
}
|
||||
|
||||
private class StringEnumDictionaryConverterInner<TKey, TValue> : JsonConverter<IDictionary<TKey, TValue>>
|
||||
where TKey : struct, Enum
|
||||
{
|
||||
private readonly JsonConverter<TValue>? valueConverter;
|
||||
private readonly Type keyType;
|
||||
private readonly Type valueType;
|
||||
|
||||
public StringEnumDictionaryConverterInner(JsonSerializerOptions options)
|
||||
{
|
||||
valueConverter = (JsonConverter<TValue>)options.GetConverter(typeof(TValue));
|
||||
|
||||
// Cache the key and value types.
|
||||
keyType = typeof(TKey);
|
||||
valueType = typeof(TValue);
|
||||
}
|
||||
|
||||
public override IDictionary<TKey, TValue> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
if (reader.TokenType != JsonTokenType.StartObject)
|
||||
{
|
||||
throw new JsonException();
|
||||
}
|
||||
|
||||
Dictionary<TKey, TValue> dictionary = new();
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
if (reader.TokenType == JsonTokenType.EndObject)
|
||||
{
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
// Get the key.
|
||||
if (reader.TokenType != JsonTokenType.PropertyName)
|
||||
{
|
||||
throw new JsonException();
|
||||
}
|
||||
|
||||
string? propertyName = reader.GetString();
|
||||
|
||||
if (!Enum.TryParse(propertyName, out TKey key))
|
||||
{
|
||||
throw new JsonException($"Unable to convert \"{propertyName}\" to Enum \"{keyType}\".");
|
||||
}
|
||||
|
||||
// Get the value.
|
||||
TValue value;
|
||||
if (valueConverter != null)
|
||||
{
|
||||
reader.Read();
|
||||
value = valueConverter.Read(ref reader, valueType, options)!;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = JsonSerializer.Deserialize<TValue>(ref reader, options)!;
|
||||
}
|
||||
|
||||
// Add to dictionary.
|
||||
dictionary.Add(key, value);
|
||||
}
|
||||
|
||||
throw new JsonException();
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, IDictionary<TKey, TValue> dictionary, JsonSerializerOptions options)
|
||||
{
|
||||
writer.WriteStartObject();
|
||||
|
||||
foreach ((TKey key, TValue value) in dictionary)
|
||||
{
|
||||
string? propertyName = key.ToString();
|
||||
string? convertedName = options.PropertyNamingPolicy?.ConvertName(propertyName) ?? propertyName;
|
||||
|
||||
writer.WritePropertyName(convertedName);
|
||||
|
||||
if (valueConverter != null)
|
||||
{
|
||||
valueConverter.Write(writer, value, options);
|
||||
}
|
||||
else
|
||||
{
|
||||
JsonSerializer.Serialize(writer, value, options);
|
||||
}
|
||||
}
|
||||
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ internal static class Property<TOwner>
|
||||
/// <returns>注册的依赖属性</returns>
|
||||
public static DependencyProperty Depend<TProperty>(string name)
|
||||
{
|
||||
return DependencyProperty.Register(name, typeof(TProperty), typeof(TOwner), new PropertyMetadata(null));
|
||||
return DependencyProperty.Register(name, typeof(TProperty), typeof(TOwner), new(default(TProperty)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -31,7 +31,7 @@ internal static class Property<TOwner>
|
||||
/// <returns>注册的依赖属性</returns>
|
||||
public static DependencyProperty Depend<TProperty>(string name, TProperty defaultValue)
|
||||
{
|
||||
return DependencyProperty.Register(name, typeof(TProperty), typeof(TOwner), new PropertyMetadata(defaultValue));
|
||||
return DependencyProperty.Register(name, typeof(TProperty), typeof(TOwner), new(defaultValue));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -44,7 +44,7 @@ internal static class Property<TOwner>
|
||||
/// <returns>注册的依赖属性</returns>
|
||||
public static DependencyProperty Depend<TProperty>(string name, TProperty defaultValue, PropertyChangedCallback callback)
|
||||
{
|
||||
return DependencyProperty.Register(name, typeof(TProperty), typeof(TOwner), new PropertyMetadata(defaultValue, callback));
|
||||
return DependencyProperty.Register(name, typeof(TProperty), typeof(TOwner), new(defaultValue, callback));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -55,7 +55,7 @@ internal static class Property<TOwner>
|
||||
/// <returns>注册的附加属性</returns>
|
||||
public static DependencyProperty Attach<TProperty>(string name)
|
||||
{
|
||||
return DependencyProperty.RegisterAttached(name, typeof(TProperty), typeof(TOwner), new PropertyMetadata(null));
|
||||
return DependencyProperty.RegisterAttached(name, typeof(TProperty), typeof(TOwner), new(default(TProperty)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -67,7 +67,7 @@ internal static class Property<TOwner>
|
||||
/// <returns>注册的附加属性</returns>
|
||||
public static DependencyProperty Attach<TProperty>(string name, TProperty defaultValue)
|
||||
{
|
||||
return DependencyProperty.RegisterAttached(name, typeof(TProperty), typeof(TOwner), new PropertyMetadata(defaultValue));
|
||||
return DependencyProperty.RegisterAttached(name, typeof(TProperty), typeof(TOwner), new(defaultValue));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -79,6 +79,6 @@ internal static class Property<TOwner>
|
||||
/// <returns>注册的附加属性</returns>
|
||||
public static DependencyProperty Attach<TProperty>(string name, PropertyChangedCallback callback)
|
||||
{
|
||||
return DependencyProperty.RegisterAttached(name, typeof(TProperty), typeof(TOwner), new PropertyMetadata(callback));
|
||||
return DependencyProperty.RegisterAttached(name, typeof(TProperty), typeof(TOwner), new(callback));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Snap.Hutao.Core.Setting;
|
||||
internal static class LocalSetting
|
||||
{
|
||||
/// <summary>
|
||||
/// 由于 <see cref="Windows.Foundation.Collections.IPropertySet"/> 没有启用 nullable,
|
||||
/// 由于 <see cref="Windows.Foundation.Collections.IPropertySet"/> 没有 nullable context,
|
||||
/// 在处理引用类型时需要格外小心
|
||||
/// 将值类型的操作与引用类型区分开,可以提升一定的性能
|
||||
/// </summary>
|
||||
|
||||
@@ -92,8 +92,9 @@ internal class AsyncRelayCommandFactory : IAsyncRelayCommandFactory
|
||||
{
|
||||
if (asyncRelayCommand.ExecutionTask?.Exception is AggregateException exception)
|
||||
{
|
||||
logger.LogError(exception, "异步命令发生了错误");
|
||||
Crashes.TrackError(exception);
|
||||
Exception baseException = exception.GetBaseException();
|
||||
logger.LogError(baseException, "异步命令发生了错误");
|
||||
Crashes.TrackError(baseException);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ global using Snap.Hutao.Core.Validation;
|
||||
global using System;
|
||||
global using System.ComponentModel;
|
||||
global using System.Diagnostics.CodeAnalysis;
|
||||
global using System.Text.Json;
|
||||
global using System.Threading;
|
||||
global using System.Threading.Tasks;
|
||||
global using System.Windows.Input;
|
||||
global using System.Windows.Input;
|
||||
@@ -7,7 +7,7 @@ using Snap.Hutao.Context.Database;
|
||||
using Snap.Hutao.Context.FileSystem;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Snap.Hutao;
|
||||
@@ -22,20 +22,20 @@ internal static class IocConfiguration
|
||||
/// </summary>
|
||||
/// <param name="services">集合</param>
|
||||
/// <returns>可继续操作的集合</returns>
|
||||
public static IServiceCollection AddDefaultJsonSerializerOptions(this IServiceCollection services)
|
||||
public static IServiceCollection AddJsonSerializerOptions(this IServiceCollection services)
|
||||
{
|
||||
// default json options, global configuration
|
||||
return services
|
||||
.AddSingleton(new JsonSerializerOptions()
|
||||
{
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
|
||||
PropertyNameCaseInsensitive = true,
|
||||
WriteIndented = true,
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加数据库
|
||||
/// 添加专用数据库
|
||||
/// </summary>
|
||||
/// <param name="services">集合</param>
|
||||
/// <returns>可继续操作的集合</returns>
|
||||
@@ -48,13 +48,12 @@ internal static class IocConfiguration
|
||||
string sqlConnectionString = $"Data Source={dbFile}";
|
||||
|
||||
// temporarily create a context
|
||||
using (AppDbContext context = AppDbContext.CreateFrom(sqlConnectionString))
|
||||
using (AppDbContext context = AppDbContext.Create(sqlConnectionString))
|
||||
{
|
||||
if (context.Database.GetPendingMigrations().Any())
|
||||
{
|
||||
Debug.WriteLine("Migrate started");
|
||||
Debug.WriteLine("Performing Migrations");
|
||||
context.Database.Migrate();
|
||||
Debug.WriteLine("Migrate completed");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Snap.Hutao.Service.Metadata;
|
||||
using Snap.Hutao.Web.Enka;
|
||||
using Snap.Hutao.Web.Hoyolab.Bbs.User;
|
||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Common.Announcement;
|
||||
using Snap.Hutao.Web.Hoyolab.Takumi.Binding;
|
||||
@@ -25,10 +27,16 @@ internal static class IocHttpClientConfiguration
|
||||
/// <returns>可继续操作的集合</returns>
|
||||
public static IServiceCollection AddHttpClients(this IServiceCollection services)
|
||||
{
|
||||
// services
|
||||
services.AddHttpClient<MetadataService>(DefaultConfiguration);
|
||||
|
||||
// normal clients
|
||||
services.AddHttpClient<HutaoClient>(DefaultConfiguration);
|
||||
services.AddHttpClient<AnnouncementClient>(DefaultConfiguration);
|
||||
services.AddHttpClient<UserGameRoleClient>(DefaultConfiguration);
|
||||
services.AddHttpClient<EnkaClient>(DefaultConfiguration);
|
||||
|
||||
// x-rpc clients
|
||||
services.AddHttpClient<GameRecordClient>(XRpcConfiguration);
|
||||
services.AddHttpClient<UserClient>(XRpcConfiguration);
|
||||
|
||||
|
||||
@@ -5,9 +5,10 @@
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:view="using:Snap.Hutao.View"
|
||||
mc:Ignorable="d">
|
||||
mc:Ignorable="d"
|
||||
Closed="MainWindowClosed">
|
||||
|
||||
<Grid>
|
||||
<Grid Background="{ThemeResource SolidBackgroundFillColorBaseBrush}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="48.8"/>
|
||||
<RowDefinition/>
|
||||
|
||||
@@ -12,24 +12,25 @@ namespace Snap.Hutao;
|
||||
[Injection(InjectAs.Singleton)]
|
||||
public sealed partial class MainWindow : Window
|
||||
{
|
||||
private readonly AppDbContext appDbContext;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的主窗体
|
||||
/// </summary>
|
||||
public MainWindow()
|
||||
/// <param name="appDbContext">数据库上下文</param>
|
||||
public MainWindow(AppDbContext appDbContext)
|
||||
{
|
||||
this.appDbContext = appDbContext;
|
||||
|
||||
InitializeComponent();
|
||||
ExtendsContentIntoTitleBar = true;
|
||||
SetTitleBar(TitleBarView.DragableArea);
|
||||
|
||||
Closed += MainWindowClosed;
|
||||
}
|
||||
|
||||
private void MainWindowClosed(object sender, WindowEventArgs args)
|
||||
{
|
||||
// save datebase
|
||||
AppDbContext appDbContext = Ioc.Default.GetRequiredService<AppDbContext>();
|
||||
int changes = appDbContext.SaveChanges();
|
||||
|
||||
Verify.Operation(changes == 0, "存在可避免的未经处理的数据库更改");
|
||||
}
|
||||
}
|
||||
46
src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/EquipType.cs
Normal file
46
src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/EquipType.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Model.Intrinsic;
|
||||
|
||||
/// <summary>
|
||||
/// 装备类型
|
||||
/// https://github.com/Grasscutters/Grasscutter/blob/development/src/main/java/emu/grasscutter/game/inventory/EquipType.java
|
||||
/// </summary>
|
||||
public enum EquipType
|
||||
{
|
||||
/// <summary>
|
||||
/// 无
|
||||
/// </summary>
|
||||
EQUIP_NONE = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 花
|
||||
/// </summary>
|
||||
EQUIP_BRACER = 1,
|
||||
|
||||
/// <summary>
|
||||
/// 羽毛
|
||||
/// </summary>
|
||||
EQUIP_NECKLACE = 2,
|
||||
|
||||
/// <summary>
|
||||
/// 沙
|
||||
/// </summary>
|
||||
EQUIP_SHOES = 3,
|
||||
|
||||
/// <summary>
|
||||
/// 杯
|
||||
/// </summary>
|
||||
EQUIP_RING = 4,
|
||||
|
||||
/// <summary>
|
||||
/// 头
|
||||
/// </summary>
|
||||
EQUIP_DRESS = 5,
|
||||
|
||||
/// <summary>
|
||||
/// 武器
|
||||
/// </summary>
|
||||
EQUIP_WEAPON = 6,
|
||||
}
|
||||
491
src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/FightProperty.cs
Normal file
491
src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/FightProperty.cs
Normal file
@@ -0,0 +1,491 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Model.Intrinsic;
|
||||
|
||||
/// <summary>
|
||||
/// 战斗属性
|
||||
/// https://github.com/Grasscutters/Grasscutter/tree/development/src/main/java/emu/grasscutter/game/props/FightProperty.java
|
||||
/// </summary>
|
||||
public enum FightProperty
|
||||
{
|
||||
/// <summary>
|
||||
/// 空
|
||||
/// </summary>
|
||||
FIGHT_PROP_NONE = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 基础生命值
|
||||
/// </summary>
|
||||
FIGHT_PROP_BASE_HP = 1,
|
||||
|
||||
/// <summary>
|
||||
/// 生命值加成
|
||||
/// </summary>
|
||||
FIGHT_PROP_HP = 2,
|
||||
|
||||
/// <summary>
|
||||
/// 生命值加成百分比
|
||||
/// </summary>
|
||||
FIGHT_PROP_HP_PERCENT = 3,
|
||||
|
||||
/// <summary>
|
||||
/// 基础攻击力
|
||||
/// </summary>
|
||||
FIGHT_PROP_BASE_ATTACK = 4,
|
||||
|
||||
/// <summary>
|
||||
/// 攻击力加成
|
||||
/// </summary>
|
||||
FIGHT_PROP_ATTACK = 5,
|
||||
|
||||
/// <summary>
|
||||
/// 攻击力百分比
|
||||
/// </summary>
|
||||
FIGHT_PROP_ATTACK_PERCENT = 6,
|
||||
|
||||
/// <summary>
|
||||
/// 基础防御力
|
||||
/// </summary>
|
||||
FIGHT_PROP_BASE_DEFENSE = 7,
|
||||
|
||||
/// <summary>
|
||||
/// 防御力加成
|
||||
/// </summary>
|
||||
FIGHT_PROP_DEFENSE = 8,
|
||||
|
||||
/// <summary>
|
||||
/// 防御力百分比
|
||||
/// </summary>
|
||||
FIGHT_PROP_DEFENSE_PERCENT = 9,
|
||||
|
||||
/// <summary>
|
||||
/// 基础速度
|
||||
/// </summary>
|
||||
FIGHT_PROP_BASE_SPEED = 10,
|
||||
|
||||
/// <summary>
|
||||
/// 速度加成
|
||||
/// </summary>
|
||||
FIGHT_PROP_SPEED_PERCENT = 11,
|
||||
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// </summary>
|
||||
FIGHT_PROP_HP_MP_PERCENT = 12,
|
||||
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// </summary>
|
||||
FIGHT_PROP_ATTACK_MP_PERCENT = 13,
|
||||
|
||||
/// <summary>
|
||||
/// 暴击率
|
||||
/// </summary>
|
||||
FIGHT_PROP_CRITICAL = 20,
|
||||
|
||||
/// <summary>
|
||||
/// 抗暴击率
|
||||
/// </summary>
|
||||
FIGHT_PROP_ANTI_CRITICAL = 21,
|
||||
|
||||
/// <summary>
|
||||
/// 暴击伤害
|
||||
/// </summary>
|
||||
FIGHT_PROP_CRITICAL_HURT = 22,
|
||||
|
||||
/// <summary>
|
||||
/// 元素充能效率
|
||||
/// </summary>
|
||||
FIGHT_PROP_CHARGE_EFFICIENCY = 23,
|
||||
|
||||
/// <summary>
|
||||
/// 伤害加成
|
||||
/// </summary>
|
||||
FIGHT_PROP_ADD_HURT = 24,
|
||||
|
||||
/// <summary>
|
||||
/// 抗性提升
|
||||
/// </summary>
|
||||
FIGHT_PROP_SUB_HURT = 25,
|
||||
|
||||
/// <summary>
|
||||
/// 治疗提升
|
||||
/// </summary>
|
||||
FIGHT_PROP_HEAL_ADD = 26,
|
||||
|
||||
/// <summary>
|
||||
/// 受治疗提升
|
||||
/// </summary>
|
||||
FIGHT_PROP_HEALED_ADD = 27,
|
||||
|
||||
/// <summary>
|
||||
/// 元素精通
|
||||
/// </summary>
|
||||
FIGHT_PROP_ELEMENT_MASTERY = 28,
|
||||
|
||||
/// <summary>
|
||||
/// 物理抗性提升
|
||||
/// </summary>
|
||||
FIGHT_PROP_PHYSICAL_SUB_HURT = 29,
|
||||
|
||||
/// <summary>
|
||||
/// 物理伤害加成
|
||||
/// </summary>
|
||||
FIGHT_PROP_PHYSICAL_ADD_HURT = 30,
|
||||
|
||||
/// <summary>
|
||||
/// 无视防御力百分比
|
||||
/// </summary>
|
||||
FIGHT_PROP_DEFENCE_IGNORE_RATIO = 31,
|
||||
|
||||
/// <summary>
|
||||
/// 防御力降低
|
||||
/// </summary>
|
||||
FIGHT_PROP_DEFENCE_IGNORE_DELTA = 32,
|
||||
|
||||
/// <summary>
|
||||
/// 火元素伤害加成
|
||||
/// </summary>
|
||||
FIGHT_PROP_FIRE_ADD_HURT = 40,
|
||||
|
||||
/// <summary>
|
||||
/// 雷元素伤害加成
|
||||
/// </summary>
|
||||
FIGHT_PROP_ELEC_ADD_HURT = 41,
|
||||
|
||||
/// <summary>
|
||||
/// 水元素伤害加成
|
||||
/// </summary>
|
||||
FIGHT_PROP_WATER_ADD_HURT = 42,
|
||||
|
||||
/// <summary>
|
||||
/// 草元素伤害加成
|
||||
/// </summary>
|
||||
FIGHT_PROP_GRASS_ADD_HURT = 43,
|
||||
|
||||
/// <summary>
|
||||
/// 风元素伤害加成
|
||||
/// </summary>
|
||||
FIGHT_PROP_WIND_ADD_HURT = 44,
|
||||
|
||||
/// <summary>
|
||||
/// 岩元素伤害加成
|
||||
/// </summary>
|
||||
FIGHT_PROP_ROCK_ADD_HURT = 45,
|
||||
|
||||
/// <summary>
|
||||
/// 冰元素伤害加成
|
||||
/// </summary>
|
||||
FIGHT_PROP_ICE_ADD_HURT = 46,
|
||||
|
||||
/// <summary>
|
||||
/// 弱点伤害加成
|
||||
/// </summary>
|
||||
FIGHT_PROP_HIT_HEAD_ADD_HURT = 47,
|
||||
|
||||
/// <summary>
|
||||
/// 火元素抗性提升
|
||||
/// </summary>
|
||||
FIGHT_PROP_FIRE_SUB_HURT = 50,
|
||||
|
||||
/// <summary>
|
||||
/// 雷元素抗性提升
|
||||
/// </summary>
|
||||
FIGHT_PROP_ELEC_SUB_HURT = 51,
|
||||
|
||||
/// <summary>
|
||||
/// 雷元素抗性提升
|
||||
/// </summary>
|
||||
FIGHT_PROP_WATER_SUB_HURT = 52,
|
||||
|
||||
/// <summary>
|
||||
/// 草元素抗性提升
|
||||
/// </summary>
|
||||
FIGHT_PROP_GRASS_SUB_HURT = 53,
|
||||
|
||||
/// <summary>
|
||||
/// 风元素抗性提升
|
||||
/// </summary>
|
||||
FIGHT_PROP_WIND_SUB_HURT = 54,
|
||||
|
||||
/// <summary>
|
||||
/// 岩元素抗性提升
|
||||
/// </summary>
|
||||
FIGHT_PROP_ROCK_SUB_HURT = 55,
|
||||
|
||||
/// <summary>
|
||||
/// 冰元素抗性提升
|
||||
/// </summary>
|
||||
FIGHT_PROP_ICE_SUB_HURT = 56,
|
||||
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// </summary>
|
||||
FIGHT_PROP_EFFECT_HIT = 60,
|
||||
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// </summary>
|
||||
FIGHT_PROP_EFFECT_RESIST = 61,
|
||||
|
||||
/// <summary>
|
||||
/// 冻结抗性
|
||||
/// </summary>
|
||||
FIGHT_PROP_FREEZE_RESIST = 62,
|
||||
|
||||
/// <summary>
|
||||
/// 迟缓抗性
|
||||
/// </summary>
|
||||
FIGHT_PROP_TORPOR_RESIST = 63,
|
||||
|
||||
/// <summary>
|
||||
/// 眩晕抗性
|
||||
/// </summary>
|
||||
FIGHT_PROP_DIZZY_RESIST = 64,
|
||||
|
||||
/// <summary>
|
||||
/// 冻结缩减
|
||||
/// </summary>
|
||||
FIGHT_PROP_FREEZE_SHORTEN = 65,
|
||||
|
||||
/// <summary>
|
||||
/// 迟缓缩减
|
||||
/// </summary>
|
||||
FIGHT_PROP_TORPOR_SHORTEN = 66,
|
||||
|
||||
/// <summary>
|
||||
/// 眩晕缩减
|
||||
/// </summary>
|
||||
FIGHT_PROP_DIZZY_SHORTEN = 67,
|
||||
|
||||
/// <summary>
|
||||
/// 火元素爆发能量
|
||||
/// </summary>
|
||||
FIGHT_PROP_MAX_FIRE_ENERGY = 70,
|
||||
|
||||
/// <summary>
|
||||
/// 雷元素爆发能量
|
||||
/// </summary>
|
||||
FIGHT_PROP_MAX_ELEC_ENERGY = 71,
|
||||
|
||||
/// <summary>
|
||||
/// 水元素爆发能量
|
||||
/// </summary>
|
||||
FIGHT_PROP_MAX_WATER_ENERGY = 72,
|
||||
|
||||
/// <summary>
|
||||
/// 草元素爆发能量
|
||||
/// </summary>
|
||||
FIGHT_PROP_MAX_GRASS_ENERGY = 73,
|
||||
|
||||
/// <summary>
|
||||
/// 风元素爆发能量
|
||||
/// </summary>
|
||||
FIGHT_PROP_MAX_WIND_ENERGY = 74,
|
||||
|
||||
/// <summary>
|
||||
/// 冰元素爆发能量
|
||||
/// </summary>
|
||||
FIGHT_PROP_MAX_ICE_ENERGY = 75,
|
||||
|
||||
/// <summary>
|
||||
/// 岩元素爆发能量
|
||||
/// </summary>
|
||||
FIGHT_PROP_MAX_ROCK_ENERGY = 76,
|
||||
|
||||
/// <summary>
|
||||
/// 技能冷却缩减
|
||||
/// </summary>
|
||||
FIGHT_PROP_SKILL_CD_MINUS_RATIO = 80,
|
||||
|
||||
/// <summary>
|
||||
/// 护盾强效
|
||||
/// </summary>
|
||||
FIGHT_PROP_SHIELD_COST_MINUS_RATIO = 81,
|
||||
|
||||
/// <summary>
|
||||
/// 火元素爆发当前能量
|
||||
/// </summary>
|
||||
FIGHT_PROP_CUR_FIRE_ENERGY = 1000,
|
||||
|
||||
/// <summary>
|
||||
/// 雷元素爆发当前能量
|
||||
/// </summary>
|
||||
FIGHT_PROP_CUR_ELEC_ENERGY = 1001,
|
||||
|
||||
/// <summary>
|
||||
/// 水元素爆发当前能量
|
||||
/// </summary>
|
||||
FIGHT_PROP_CUR_WATER_ENERGY = 1002,
|
||||
|
||||
/// <summary>
|
||||
/// 草元素爆发当前能量
|
||||
/// </summary>
|
||||
FIGHT_PROP_CUR_GRASS_ENERGY = 1003,
|
||||
|
||||
/// <summary>
|
||||
/// 风元素爆发当前能量
|
||||
/// </summary>
|
||||
FIGHT_PROP_CUR_WIND_ENERGY = 1004,
|
||||
|
||||
/// <summary>
|
||||
/// 冰元素爆发当前能量
|
||||
/// </summary>
|
||||
FIGHT_PROP_CUR_ICE_ENERGY = 1005,
|
||||
|
||||
/// <summary>
|
||||
/// 岩元素爆发当前能量
|
||||
/// </summary>
|
||||
FIGHT_PROP_CUR_ROCK_ENERGY = 1006,
|
||||
|
||||
/// <summary>
|
||||
/// 当前生命值
|
||||
/// </summary>
|
||||
FIGHT_PROP_CUR_HP = 1010,
|
||||
|
||||
/// <summary>
|
||||
/// 最大生命值
|
||||
/// </summary>
|
||||
FIGHT_PROP_MAX_HP = 2000,
|
||||
|
||||
/// <summary>
|
||||
/// 当前攻击力
|
||||
/// </summary>
|
||||
FIGHT_PROP_CUR_ATTACK = 2001,
|
||||
|
||||
/// <summary>
|
||||
/// 当前防御力
|
||||
/// </summary>
|
||||
FIGHT_PROP_CUR_DEFENSE = 2002,
|
||||
|
||||
/// <summary>
|
||||
/// 当前速度
|
||||
/// </summary>
|
||||
FIGHT_PROP_CUR_SPEED = 2003,
|
||||
|
||||
/// <summary>
|
||||
/// 总攻击力
|
||||
/// </summary>
|
||||
FIGHT_PROP_NONEXTRA_ATTACK = 3000,
|
||||
|
||||
/// <summary>
|
||||
/// 总防御力
|
||||
/// </summary>
|
||||
FIGHT_PROP_NONEXTRA_DEFENSE = 3001,
|
||||
|
||||
/// <summary>
|
||||
/// 总暴击率
|
||||
/// </summary>
|
||||
FIGHT_PROP_NONEXTRA_CRITICAL = 3002,
|
||||
|
||||
/// <summary>
|
||||
/// 总抗暴击率
|
||||
/// </summary>
|
||||
FIGHT_PROP_NONEXTRA_ANTI_CRITICAL = 3003,
|
||||
|
||||
/// <summary>
|
||||
/// 总暴击伤害
|
||||
/// </summary>
|
||||
FIGHT_PROP_NONEXTRA_CRITICAL_HURT = 3004,
|
||||
|
||||
/// <summary>
|
||||
/// 总元素充能效率
|
||||
/// </summary>
|
||||
FIGHT_PROP_NONEXTRA_CHARGE_EFFICIENCY = 3005,
|
||||
|
||||
/// <summary>
|
||||
/// 元素精通
|
||||
/// </summary>
|
||||
FIGHT_PROP_NONEXTRA_ELEMENT_MASTERY = 3006,
|
||||
|
||||
/// <summary>
|
||||
/// 总物理抗性提升
|
||||
/// </summary>
|
||||
FIGHT_PROP_NONEXTRA_PHYSICAL_SUB_HURT = 3007,
|
||||
|
||||
/// <summary>
|
||||
/// 总火元素伤害提升
|
||||
/// </summary>
|
||||
FIGHT_PROP_NONEXTRA_FIRE_ADD_HURT = 3008,
|
||||
|
||||
/// <summary>
|
||||
/// 总雷元素伤害加成
|
||||
/// </summary>
|
||||
FIGHT_PROP_NONEXTRA_ELEC_ADD_HURT = 3009,
|
||||
|
||||
/// <summary>
|
||||
/// 总水元素伤害加成
|
||||
/// </summary>
|
||||
FIGHT_PROP_NONEXTRA_WATER_ADD_HURT = 3010,
|
||||
|
||||
/// <summary>
|
||||
/// 总草元素伤害加成
|
||||
/// </summary>
|
||||
FIGHT_PROP_NONEXTRA_GRASS_ADD_HURT = 3011,
|
||||
|
||||
/// <summary>
|
||||
/// 总风元素伤害加成
|
||||
/// </summary>
|
||||
FIGHT_PROP_NONEXTRA_WIND_ADD_HURT = 3012,
|
||||
|
||||
/// <summary>
|
||||
/// 总岩元素伤害加成
|
||||
/// </summary>
|
||||
FIGHT_PROP_NONEXTRA_ROCK_ADD_HURT = 3013,
|
||||
|
||||
/// <summary>
|
||||
/// 总冰元素伤害加成
|
||||
/// </summary>
|
||||
FIGHT_PROP_NONEXTRA_ICE_ADD_HURT = 3014,
|
||||
|
||||
/// <summary>
|
||||
/// 总火元素抗性提升
|
||||
/// </summary>
|
||||
FIGHT_PROP_NONEXTRA_FIRE_SUB_HURT = 3015,
|
||||
|
||||
/// <summary>
|
||||
/// 总雷元素抗性提升
|
||||
/// </summary>
|
||||
FIGHT_PROP_NONEXTRA_ELEC_SUB_HURT = 3016,
|
||||
|
||||
/// <summary>
|
||||
/// 总水元素抗性提升
|
||||
/// </summary>
|
||||
FIGHT_PROP_NONEXTRA_WATER_SUB_HURT = 3017,
|
||||
|
||||
/// <summary>
|
||||
/// 总草元素抗性提升
|
||||
/// </summary>
|
||||
FIGHT_PROP_NONEXTRA_GRASS_SUB_HURT = 3018,
|
||||
|
||||
/// <summary>
|
||||
/// 总风元素抗性提升
|
||||
/// </summary>
|
||||
FIGHT_PROP_NONEXTRA_WIND_SUB_HURT = 3019,
|
||||
|
||||
/// <summary>
|
||||
/// 总岩元素抗性提升
|
||||
/// </summary>
|
||||
FIGHT_PROP_NONEXTRA_ROCK_SUB_HURT = 3020,
|
||||
|
||||
/// <summary>
|
||||
/// 总冰元素抗性提升
|
||||
/// </summary>
|
||||
FIGHT_PROP_NONEXTRA_ICE_SUB_HURT = 3021,
|
||||
|
||||
/// <summary>
|
||||
/// 总冷却缩减
|
||||
/// </summary>
|
||||
FIGHT_PROP_NONEXTRA_SKILL_CD_MINUS_RATIO = 3022,
|
||||
|
||||
/// <summary>
|
||||
/// 总护盾强效
|
||||
/// </summary>
|
||||
FIGHT_PROP_NONEXTRA_SHIELD_COST_MINUS_RATIO = 3023,
|
||||
|
||||
/// <summary>
|
||||
/// 总物理伤害加成
|
||||
/// </summary>
|
||||
FIGHT_PROP_NONEXTRA_PHYSICAL_ADD_HURT = 3024,
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Avatar;
|
||||
namespace Snap.Hutao.Model.Intrinsic;
|
||||
|
||||
/// <summary>
|
||||
/// 稀有度
|
||||
46
src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/ItemType.cs
Normal file
46
src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/ItemType.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Model.Intrinsic;
|
||||
|
||||
/// <summary>
|
||||
/// 物品类型
|
||||
/// https://github.com/Grasscutters/Grasscutter/tree/development/src/main/java/emu/grasscutter/game/inventory/ItemType.java
|
||||
/// </summary>
|
||||
public enum ItemType
|
||||
{
|
||||
/// <summary>
|
||||
/// 无
|
||||
/// </summary>
|
||||
ITEM_NONE = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 贵重道具
|
||||
/// </summary>
|
||||
ITEM_VIRTUAL = 1,
|
||||
|
||||
/// <summary>
|
||||
/// 材料
|
||||
/// </summary>
|
||||
ITEM_MATERIAL = 2,
|
||||
|
||||
/// <summary>
|
||||
/// 圣遗物
|
||||
/// </summary>
|
||||
ITEM_RELIQUARY = 3,
|
||||
|
||||
/// <summary>
|
||||
/// 武器
|
||||
/// </summary>
|
||||
ITEM_WEAPON = 4,
|
||||
|
||||
/// <summary>
|
||||
/// 任务等
|
||||
/// </summary>
|
||||
ITEM_DISPLAY = 5,
|
||||
|
||||
/// <summary>
|
||||
/// 家具
|
||||
/// </summary>
|
||||
ITEM_FURNITURE = 6,
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Avatar;
|
||||
namespace Snap.Hutao.Model.Intrinsic;
|
||||
|
||||
/// <summary>
|
||||
/// 武器类型
|
||||
@@ -0,0 +1,57 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Achievement;
|
||||
|
||||
/// <summary>
|
||||
/// 成就
|
||||
/// </summary>
|
||||
public class Achievement
|
||||
{
|
||||
/// <summary>
|
||||
/// Id
|
||||
/// </summary>
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 分类Id
|
||||
/// </summary>
|
||||
public int Goal { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 排序顺序
|
||||
/// </summary>
|
||||
public int Order { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标题
|
||||
/// </summary>
|
||||
public string Title { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 描述
|
||||
/// </summary>
|
||||
public string Description { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 完成奖励
|
||||
/// </summary>
|
||||
public Reward FinishReward { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 总进度
|
||||
/// </summary>
|
||||
public int Progress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 触发器
|
||||
/// </summary>
|
||||
public IEnumerable<AchievementTrigger>? Triggers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 图标
|
||||
/// </summary>
|
||||
public string? Icon { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Achievement;
|
||||
|
||||
/// <summary>
|
||||
/// 成就分类
|
||||
/// </summary>
|
||||
public class AchievementGoal
|
||||
{
|
||||
/// <summary>
|
||||
/// 排序顺序
|
||||
/// </summary>
|
||||
public int Order { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
public string Name { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 完成奖励
|
||||
/// </summary>
|
||||
public Reward? FinishReward { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 图标
|
||||
/// </summary>
|
||||
public string? Icon { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Achievement;
|
||||
|
||||
/// <summary>
|
||||
/// 成就触发器
|
||||
/// </summary>
|
||||
public class AchievementTrigger
|
||||
{
|
||||
/// <summary>
|
||||
/// 触发器类型
|
||||
/// </summary>
|
||||
public AchievementTriggerType Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Id
|
||||
/// </summary>
|
||||
public string Id { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 标题
|
||||
/// </summary>
|
||||
public string Title { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 描述
|
||||
/// </summary>
|
||||
public string Description { get; set; } = default!;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Achievement;
|
||||
|
||||
/// <summary>
|
||||
/// 成就触发器类型
|
||||
/// </summary>
|
||||
public enum AchievementTriggerType
|
||||
{
|
||||
/// <summary>
|
||||
/// 任务
|
||||
/// </summary>
|
||||
Quest = 1,
|
||||
|
||||
/// <summary>
|
||||
/// 子任务
|
||||
/// </summary>
|
||||
SubQuest = 2,
|
||||
|
||||
/// <summary>
|
||||
/// 日常任务
|
||||
/// </summary>
|
||||
DailyTask = 3,
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Achievement;
|
||||
|
||||
/// <summary>
|
||||
/// 奖励
|
||||
/// </summary>
|
||||
public class Reward
|
||||
{
|
||||
/// <summary>
|
||||
/// Id
|
||||
/// </summary>
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数量
|
||||
/// </summary>
|
||||
public int Count { get; set; }
|
||||
}
|
||||
83
src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/Avatar.cs
Normal file
83
src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/Avatar.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Avatar;
|
||||
|
||||
/// <summary>
|
||||
/// 角色
|
||||
/// </summary>
|
||||
public class Avatar
|
||||
{
|
||||
/// <summary>
|
||||
/// Id
|
||||
/// </summary>
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 排序号
|
||||
/// </summary>
|
||||
public int Sort { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 体型
|
||||
/// </summary>
|
||||
public string Body { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 正面图标
|
||||
/// </summary>
|
||||
public string Icon { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 侧面图标
|
||||
/// </summary>
|
||||
public string SideIcon { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
public string Name { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 描述
|
||||
/// </summary>
|
||||
public string Description { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 角色加入游戏时间
|
||||
/// </summary>
|
||||
public DateTimeOffset BeginTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 星级
|
||||
/// </summary>
|
||||
public ItemQuality Quality { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 武器类型
|
||||
/// </summary>
|
||||
public WeaponType Weapon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 属性
|
||||
/// </summary>
|
||||
public PropertyInfo Property { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 技能
|
||||
/// </summary>
|
||||
public SkillDepot SkillDepot { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 好感信息
|
||||
/// </summary>
|
||||
public FetterInfo FetterInfo { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 皮肤
|
||||
/// </summary>
|
||||
public IEnumerable<Costume> Costumes { get; set; } = default!;
|
||||
}
|
||||
30
src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/Costume.cs
Normal file
30
src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/Costume.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Avatar;
|
||||
|
||||
/// <summary>
|
||||
/// 皮肤
|
||||
/// </summary>
|
||||
public class Costume
|
||||
{
|
||||
/// <summary>
|
||||
/// Id
|
||||
/// </summary>
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
public string Name { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 描述
|
||||
/// </summary>
|
||||
public string Description { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 是否为默认
|
||||
/// </summary>
|
||||
public bool IsDefault { get; set; }
|
||||
}
|
||||
22
src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/DescParam.cs
Normal file
22
src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/DescParam.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Avatar;
|
||||
|
||||
/// <summary>
|
||||
/// 描述与参数
|
||||
/// </summary>
|
||||
public class DescParam
|
||||
{
|
||||
/// <summary>
|
||||
/// 描述
|
||||
/// </summary>
|
||||
public IEnumerable<string> Descriptions { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 参数
|
||||
/// </summary>
|
||||
public IEnumerable<LevelParam<int>> Parameters { get; set; } = default!;
|
||||
}
|
||||
20
src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/Fetter.cs
Normal file
20
src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/Fetter.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Avatar;
|
||||
|
||||
/// <summary>
|
||||
/// 好感故事
|
||||
/// </summary>
|
||||
public class Fetter
|
||||
{
|
||||
/// <summary>
|
||||
/// 标题
|
||||
/// </summary>
|
||||
public string Title { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 上下文
|
||||
/// </summary>
|
||||
public string Context { get; set; } = default!;
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Avatar;
|
||||
|
||||
/// <summary>
|
||||
/// 好感信息
|
||||
/// </summary>
|
||||
public class FetterInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 称号
|
||||
/// </summary>
|
||||
public string Title { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 详细
|
||||
/// </summary>
|
||||
public string Detail { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 地区
|
||||
/// </summary>
|
||||
public string Association { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 属于组织
|
||||
/// </summary>
|
||||
public string Native { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 生月
|
||||
/// </summary>
|
||||
public int BirthMonth { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 生日
|
||||
/// </summary>
|
||||
public int BirthDay { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 神之眼属性-前
|
||||
/// </summary>
|
||||
public string VisionBefore { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 神之眼属性-后
|
||||
/// </summary>
|
||||
public string VisionAfter { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 命座-前
|
||||
/// </summary>
|
||||
public string ConstellationBefore { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 命座-后
|
||||
/// </summary>
|
||||
public string ConstellationAfter { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 中文CV
|
||||
/// </summary>
|
||||
public string CvChinese { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 日语CV
|
||||
/// </summary>
|
||||
public string CvJapanese { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 英语CV
|
||||
/// </summary>
|
||||
public string CvEnglish { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 韩语CV
|
||||
/// </summary>
|
||||
public string CvKorean { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 好感语音
|
||||
/// </summary>
|
||||
public IEnumerable<Fetter> Fetters { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 好感故事
|
||||
/// </summary>
|
||||
public IEnumerable<Fetter> FetterStories { get; set; } = default!;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Avatar;
|
||||
|
||||
/// <summary>
|
||||
/// 技能信息
|
||||
/// </summary>
|
||||
public class ProudableSkill : SkillBase
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 组Id
|
||||
/// </summary>
|
||||
public int GroupId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 提升属性
|
||||
/// </summary>
|
||||
public DescParam Proud { get; set; } = default!;
|
||||
}
|
||||
31
src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/SkillBase.cs
Normal file
31
src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/SkillBase.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Avatar;
|
||||
|
||||
/// <summary>
|
||||
/// 技能基础
|
||||
/// 命座
|
||||
/// </summary>
|
||||
public class SkillBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Id
|
||||
/// </summary>
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
public string Name { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 描述
|
||||
/// </summary>
|
||||
public string Description { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 图标
|
||||
/// </summary>
|
||||
public string Icon { get; set; } = default!;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Avatar;
|
||||
|
||||
/// <summary>
|
||||
/// 技能组
|
||||
/// </summary>
|
||||
public class SkillDepot
|
||||
{
|
||||
/// <summary>
|
||||
/// 技能天赋
|
||||
/// </summary>
|
||||
public IEnumerable<ProudableSkill> Skills { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 大招
|
||||
/// </summary>
|
||||
public ProudableSkill EnergySkill { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 固有天赋
|
||||
/// </summary>
|
||||
public IEnumerable<ProudableSkill> Inherents { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 命之座
|
||||
/// </summary>
|
||||
public IEnumerable<SkillBase> Talents { get; set; } = default!;
|
||||
}
|
||||
23
src/Snap.Hutao/Snap.Hutao/Model/Metadata/LevelParam.cs
Normal file
23
src/Snap.Hutao/Snap.Hutao/Model/Metadata/LevelParam.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata;
|
||||
|
||||
/// <summary>
|
||||
/// 等级与参数
|
||||
/// </summary>
|
||||
/// <typeparam name="TLevel">等级的类型</typeparam>
|
||||
public class LevelParam<TLevel>
|
||||
{
|
||||
/// <summary>
|
||||
/// 等级
|
||||
/// </summary>
|
||||
public TLevel Level { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 参数
|
||||
/// </summary>
|
||||
public IEnumerable<double> Parameters { get; set; } = default!;
|
||||
}
|
||||
23
src/Snap.Hutao/Snap.Hutao/Model/Metadata/PropertyInfo.cs
Normal file
23
src/Snap.Hutao/Snap.Hutao/Model/Metadata/PropertyInfo.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata;
|
||||
|
||||
/// <summary>
|
||||
/// 属性信息
|
||||
/// </summary>
|
||||
public class PropertyInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 提升的属性
|
||||
/// </summary>
|
||||
public IEnumerable<FightProperty> Properties { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 参数
|
||||
/// </summary>
|
||||
public IEnumerable<LevelParam<string>> Parameters { get; set; } = default!;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Reliquary;
|
||||
|
||||
/// <summary>
|
||||
/// 圣遗物信息
|
||||
/// </summary>
|
||||
public class Reliquary
|
||||
{
|
||||
/// <summary>
|
||||
/// 表示同种类的Id
|
||||
/// </summary>
|
||||
public IEnumerable<int> Ids { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 允许出现的等级
|
||||
/// </summary>
|
||||
public IEnumerable<ItemQuality> RankLevels { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 套装Id
|
||||
/// </summary>
|
||||
public int SetId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 装备类型
|
||||
/// </summary>
|
||||
public EquipType EquipType { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 物品类型
|
||||
/// </summary>
|
||||
public ItemType ItemType { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
public string Name { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 描述
|
||||
/// </summary>
|
||||
public string Description { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 图标
|
||||
/// </summary>
|
||||
public string Icon { get; set; } = default!;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Reliquary;
|
||||
|
||||
/// <summary>
|
||||
/// 圣遗物突破属性
|
||||
/// </summary>
|
||||
public class ReliquaryAffix : ReliquaryAffixBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 值
|
||||
/// </summary>
|
||||
public double Value { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Reliquary;
|
||||
|
||||
/// <summary>
|
||||
/// 圣遗物主属性
|
||||
/// </summary>
|
||||
public class ReliquaryAffixBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Id
|
||||
/// </summary>
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 战斗属性
|
||||
/// </summary>
|
||||
public FightProperty Type { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Reliquary;
|
||||
|
||||
/// <summary>
|
||||
/// 圣遗物套装
|
||||
/// </summary>
|
||||
public class ReliquarySet
|
||||
{
|
||||
/// <summary>
|
||||
/// 套装Id
|
||||
/// </summary>
|
||||
public int SetId { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 需要的数量
|
||||
/// </summary>
|
||||
public IEnumerable<int> NeedNumber { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 描述
|
||||
/// </summary>
|
||||
public IEnumerable<string> Descriptions { get; set; } = default!;
|
||||
}
|
||||
52
src/Snap.Hutao/Snap.Hutao/Model/Metadata/Weapon/Weapon.cs
Normal file
52
src/Snap.Hutao/Snap.Hutao/Model/Metadata/Weapon/Weapon.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
|
||||
namespace Snap.Hutao.Model.Metadata.Weapon;
|
||||
|
||||
/// <summary>
|
||||
/// 武器
|
||||
/// </summary>
|
||||
public class Weapon
|
||||
{
|
||||
/// <summary>
|
||||
/// Id
|
||||
/// </summary>
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 武器类型
|
||||
/// </summary>
|
||||
public WeaponType WeaponType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 等级
|
||||
/// </summary>
|
||||
public ItemQuality RankLevel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
public string Name { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 描述
|
||||
/// </summary>
|
||||
public string Description { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 图标
|
||||
/// </summary>
|
||||
public string Icon { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 觉醒图标
|
||||
/// </summary>
|
||||
public string AwakenIcon { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 属性
|
||||
/// </summary>
|
||||
public PropertyInfo Property { get; set; } = default!;
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
<Identity
|
||||
Name="7f0db578-026f-4e0b-a75b-d5d06bb0a74d"
|
||||
Publisher="CN=DGP Studio"
|
||||
Version="1.0.4.0" />
|
||||
Version="1.0.6.0" />
|
||||
|
||||
<Properties>
|
||||
<DisplayName>胡桃</DisplayName>
|
||||
@@ -32,13 +32,20 @@
|
||||
EntryPoint="$targetentrypoint$">
|
||||
<uap:VisualElements
|
||||
DisplayName="胡桃"
|
||||
Description="Snap Genshin 但是 WinUI3"
|
||||
Description="A Snap Hutao Software"
|
||||
BackgroundColor="transparent"
|
||||
Square150x150Logo="Assets\Square150x150Logo.png"
|
||||
Square44x44Logo="Assets\Square44x44Logo.png">
|
||||
<uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png" />
|
||||
<uap:SplashScreen Image="Assets\SplashScreen.png" />
|
||||
</uap:VisualElements>
|
||||
<Extensions>
|
||||
<uap:Extension Category="windows.protocol">
|
||||
<uap:Protocol Name="hutao">
|
||||
<uap:DisplayName>胡桃</uap:DisplayName>
|
||||
</uap:Protocol>
|
||||
</uap:Extension>
|
||||
</Extensions>
|
||||
</Application>
|
||||
</Applications>
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@ public static class Program
|
||||
private static void Main(string[] args)
|
||||
{
|
||||
XamlCheckProcessRequirements();
|
||||
|
||||
ComWrappersSupport.InitializeComWrappers();
|
||||
|
||||
Application.Start(p =>
|
||||
{
|
||||
DispatcherQueueSynchronizationContext context = new(DispatcherQueue.GetForCurrentThread());
|
||||
|
||||
@@ -45,7 +45,7 @@ public interface IInfoBarService
|
||||
/// </summary>
|
||||
/// <param name="message">消息</param>
|
||||
/// <param name="delay">关闭延迟</param>
|
||||
void Information(string message, int delay = 3000);
|
||||
void Information(string message, int delay = 5000);
|
||||
|
||||
/// <summary>
|
||||
/// 显示提示信息
|
||||
@@ -53,7 +53,7 @@ public interface IInfoBarService
|
||||
/// <param name="title">标题</param>
|
||||
/// <param name="message">消息</param>
|
||||
/// <param name="delay">关闭延迟</param>
|
||||
void Information(string title, string message, int delay = 3000);
|
||||
void Information(string title, string message, int delay = 5000);
|
||||
|
||||
/// <summary>
|
||||
/// 使用指定的 <see cref="StackPanel"/> 初始化服务
|
||||
@@ -66,7 +66,7 @@ public interface IInfoBarService
|
||||
/// </summary>
|
||||
/// <param name="message">消息</param>
|
||||
/// <param name="delay">关闭延迟</param>
|
||||
void Success(string message, int delay = 3000);
|
||||
void Success(string message, int delay = 5000);
|
||||
|
||||
/// <summary>
|
||||
/// 显示成功信息
|
||||
@@ -74,7 +74,7 @@ public interface IInfoBarService
|
||||
/// <param name="title">标题</param>
|
||||
/// <param name="message">消息</param>
|
||||
/// <param name="delay">关闭延迟</param>
|
||||
void Success(string title, string message, int delay = 3000);
|
||||
void Success(string title, string message, int delay = 5000);
|
||||
|
||||
/// <summary>
|
||||
/// 显示警告信息
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Metadata.Achievement;
|
||||
using Snap.Hutao.Model.Metadata.Avatar;
|
||||
using Snap.Hutao.Model.Metadata.Reliquary;
|
||||
using Snap.Hutao.Model.Metadata.Weapon;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Snap.Hutao.Service.Metadata;
|
||||
|
||||
/// <summary>
|
||||
/// 元数据服务
|
||||
/// </summary>
|
||||
internal interface IMetadataService
|
||||
{
|
||||
/// <summary>
|
||||
/// 异步初始化服务,尝试更新元数据
|
||||
/// </summary>
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>初始化是否成功</returns>
|
||||
ValueTask<bool> InitializeAsync(CancellationToken token = default);
|
||||
|
||||
/// <summary>
|
||||
/// 异步获取成就列表
|
||||
/// </summary>
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>成就列表</returns>
|
||||
ValueTask<IEnumerable<Achievement>> GetAchievementsAsync(CancellationToken token = default);
|
||||
|
||||
/// <summary>
|
||||
/// 异步获取成就分类列表
|
||||
/// </summary>
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>成就分类列表</returns>
|
||||
ValueTask<IEnumerable<AchievementGoal>> GetAchievementGoalsAsync(CancellationToken token = default);
|
||||
|
||||
/// <summary>
|
||||
/// 异步获取角色列表
|
||||
/// </summary>
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>角色列表</returns>
|
||||
ValueTask<IEnumerable<Avatar>> GetAvatarsAsync(CancellationToken token = default);
|
||||
|
||||
/// <summary>
|
||||
/// 异步获取圣遗物列表
|
||||
/// </summary>
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>圣遗物列表</returns>
|
||||
ValueTask<IEnumerable<Reliquary>> GetReliquariesAsync(CancellationToken token = default);
|
||||
|
||||
/// <summary>
|
||||
/// 异步获取圣遗物强化属性列表
|
||||
/// </summary>
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>圣遗物强化属性列表</returns>
|
||||
ValueTask<IEnumerable<ReliquaryAffix>> GetReliquaryAffixesAsync(CancellationToken token = default);
|
||||
|
||||
/// <summary>
|
||||
/// 异步获取圣遗物主属性强化属性列表
|
||||
/// </summary>
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>圣遗物强化属性列表</returns>
|
||||
ValueTask<IEnumerable<ReliquaryAffixBase>> GetReliquaryMainAffixesAsync(CancellationToken token = default);
|
||||
|
||||
/// <summary>
|
||||
/// 异步获取武器列表
|
||||
/// </summary>
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>武器列表</returns>
|
||||
ValueTask<IEnumerable<Weapon>> GetWeaponsAsync(CancellationToken token = default);
|
||||
|
||||
/// <summary>
|
||||
/// 异步更新元数据
|
||||
/// </summary>
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>更新是否完成</returns>
|
||||
Task<bool> UpdateMetadataAsync(CancellationToken token = default);
|
||||
}
|
||||
@@ -14,7 +14,7 @@ namespace Snap.Hutao.Service;
|
||||
[Injection(InjectAs.Transient, typeof(IAnnouncementService))]
|
||||
internal class AnnouncementService : IAnnouncementService
|
||||
{
|
||||
private const string CacheKey = $"{nameof(IAnnouncementService)}.Cache.{nameof(AnnouncementWrapper)}";
|
||||
private const string CacheKey = $"{nameof(AnnouncementService)}.Cache.{nameof(AnnouncementWrapper)}";
|
||||
|
||||
private readonly AnnouncementClient announcementClient;
|
||||
private readonly IMemoryCache memoryCache;
|
||||
|
||||
@@ -19,25 +19,25 @@ internal class InfoBarService : IInfoBarService
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Information(string message, int delay = 3000)
|
||||
public void Information(string message, int delay = 5000)
|
||||
{
|
||||
PrepareInfoBarAndShow(InfoBarSeverity.Informational, null, message, delay);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Information(string title, string message, int delay = 3000)
|
||||
public void Information(string title, string message, int delay = 5000)
|
||||
{
|
||||
PrepareInfoBarAndShow(InfoBarSeverity.Informational, title, message, delay);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Success(string message, int delay = 3000)
|
||||
public void Success(string message, int delay = 5000)
|
||||
{
|
||||
PrepareInfoBarAndShow(InfoBarSeverity.Success, null, message, delay);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Success(string title, string message, int delay = 3000)
|
||||
public void Success(string title, string message, int delay = 5000)
|
||||
{
|
||||
PrepareInfoBarAndShow(InfoBarSeverity.Success, title, message, delay);
|
||||
}
|
||||
|
||||
249
src/Snap.Hutao/Snap.Hutao/Service/MetadataService.cs
Normal file
249
src/Snap.Hutao/Snap.Hutao/Service/MetadataService.cs
Normal file
@@ -0,0 +1,249 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Snap.Hutao.Context.FileSystem;
|
||||
using Snap.Hutao.Core.Abstraction;
|
||||
using Snap.Hutao.Model.Metadata.Achievement;
|
||||
using Snap.Hutao.Model.Metadata.Avatar;
|
||||
using Snap.Hutao.Model.Metadata.Reliquary;
|
||||
using Snap.Hutao.Model.Metadata.Weapon;
|
||||
using Snap.Hutao.Service.Abstraction;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace Snap.Hutao.Service.Metadata;
|
||||
|
||||
/// <summary>
|
||||
/// 元数据服务
|
||||
/// </summary>
|
||||
[Injection(InjectAs.Singleton, typeof(IMetadataService))]
|
||||
internal class MetadataService : IMetadataService, ISupportAsyncInitialization
|
||||
{
|
||||
private const string MetaAPIHost = "http://hutao-metadata.snapgenshin.com";
|
||||
private const string MetaFileName = "Meta.json";
|
||||
private readonly IInfoBarService infoBarService;
|
||||
private readonly HttpClient httpClient;
|
||||
private readonly FileSystemContext metadataContext;
|
||||
private readonly JsonSerializerOptions options;
|
||||
private readonly ILogger<MetadataService> logger;
|
||||
private readonly IMemoryCache memoryCache;
|
||||
|
||||
private bool isInitialized = false;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的元数据服务
|
||||
/// </summary>
|
||||
/// <param name="infoBarService">信息条服务</param>
|
||||
/// <param name="httpClient">http客户端</param>
|
||||
/// <param name="metadataContext">我的文档上下文</param>
|
||||
/// <param name="options">json序列化选项</param>
|
||||
/// <param name="logger">日志器</param>
|
||||
/// <param name="memoryCache">内存缓存</param>
|
||||
public MetadataService(
|
||||
IInfoBarService infoBarService,
|
||||
HttpClient httpClient,
|
||||
MetadataContext metadataContext,
|
||||
JsonSerializerOptions options,
|
||||
ILogger<MetadataService> logger,
|
||||
IMemoryCache memoryCache)
|
||||
{
|
||||
this.infoBarService = infoBarService;
|
||||
this.httpClient = httpClient;
|
||||
this.metadataContext = metadataContext;
|
||||
this.options = options;
|
||||
this.logger = logger;
|
||||
this.memoryCache = memoryCache;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool IsInitialized { get => isInitialized; private set => isInitialized = value; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async ValueTask<bool> InitializeAsync(CancellationToken token = default)
|
||||
{
|
||||
if (IsInitialized)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
metadataContext.EnsureDirectory();
|
||||
if (metadataContext.FileExists(MetaFileName))
|
||||
{
|
||||
IDictionary<string, string>? metaMd5Map;
|
||||
using (Stream metaFile = metadataContext.OpenRead(MetaFileName))
|
||||
{
|
||||
metaMd5Map = await JsonSerializer
|
||||
.DeserializeAsync<IDictionary<string, string>>(metaFile, options, token)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await CheckMetadataAsync(Must.NotNull(metaMd5Map!), token)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
IsInitialized = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
IsInitialized = await UpdateMetadataAsync(token)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
return IsInitialized;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<bool> UpdateMetadataAsync(CancellationToken token = default)
|
||||
{
|
||||
IDictionary<string, string>? metaMd5Map = await httpClient
|
||||
.GetFromJsonAsync<IDictionary<string, string>>($"{MetaAPIHost}/{MetaFileName}", options, token)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (metaMd5Map is null)
|
||||
{
|
||||
infoBarService.Error("元数据校验文件解析失败");
|
||||
return false;
|
||||
}
|
||||
|
||||
await CheckMetadataAsync(metaMd5Map, token).ConfigureAwait(false);
|
||||
|
||||
using (FileStream metaFileStream = metadataContext.Create(MetaFileName))
|
||||
{
|
||||
await JsonSerializer
|
||||
.SerializeAsync(metaFileStream, metaMd5Map, options, token)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ValueTask<IEnumerable<AchievementGoal>> GetAchievementGoalsAsync(CancellationToken token = default)
|
||||
{
|
||||
return GetMetadataAsync<IEnumerable<AchievementGoal>>("AchievementGoal", token);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ValueTask<IEnumerable<Achievement>> GetAchievementsAsync(CancellationToken token = default)
|
||||
{
|
||||
return GetMetadataAsync<IEnumerable<Achievement>>("Achievement", token);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ValueTask<IEnumerable<Avatar>> GetAvatarsAsync(CancellationToken token = default)
|
||||
{
|
||||
return GetMetadataAsync<IEnumerable<Avatar>>("Avatar", token);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ValueTask<IEnumerable<Reliquary>> GetReliquariesAsync(CancellationToken token = default)
|
||||
{
|
||||
return GetMetadataAsync<IEnumerable<Reliquary>>("Reliquary", token);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ValueTask<IEnumerable<ReliquaryAffix>> GetReliquaryAffixesAsync(CancellationToken token = default)
|
||||
{
|
||||
return GetMetadataAsync<IEnumerable<ReliquaryAffix>>("ReliquaryAffix", token);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ValueTask<IEnumerable<ReliquaryAffixBase>> GetReliquaryMainAffixesAsync(CancellationToken token = default)
|
||||
{
|
||||
return GetMetadataAsync<IEnumerable<ReliquaryAffixBase>>("ReliquaryMainAffix", token);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ValueTask<IEnumerable<Weapon>> GetWeaponsAsync(CancellationToken token = default)
|
||||
{
|
||||
return GetMetadataAsync<IEnumerable<Weapon>>("Weapon", token);
|
||||
}
|
||||
|
||||
private async ValueTask<T> GetMetadataAsync<T>(string fileName, CancellationToken token)
|
||||
where T : class
|
||||
{
|
||||
Verify.Operation(IsInitialized, "元数据服务尚未初始化,或初始化失败");
|
||||
string cacheKey = $"{nameof(MetadataService)}.Cache.{fileName}";
|
||||
|
||||
if (memoryCache.TryGetValue(cacheKey, out object? value))
|
||||
{
|
||||
return Must.NotNull((value as T)!);
|
||||
}
|
||||
|
||||
T? result = await JsonSerializer
|
||||
.DeserializeAsync<T>(metadataContext.OpenRead($"{fileName}.json"), options, token)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return memoryCache.Set(cacheKey, Must.NotNull(result!));
|
||||
}
|
||||
|
||||
private async Task<string> GetFileMd5Async(string fileFullName, CancellationToken token)
|
||||
{
|
||||
using (FileStream stream = metadataContext.OpenRead(fileFullName))
|
||||
{
|
||||
byte[] bytes = await MD5.Create()
|
||||
.ComputeHashAsync(stream, token)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
return Convert.ToHexString(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查元数据的Md5值是否匹配
|
||||
/// 如果不匹配则尝试下载
|
||||
/// </summary>
|
||||
/// <param name="metaMd5Map">元数据校验表</param>
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>令牌</returns>
|
||||
private async Task CheckMetadataAsync(IDictionary<string, string> metaMd5Map, CancellationToken token)
|
||||
{
|
||||
// enumerate files and compare md5
|
||||
foreach ((string fileName, string md5) in metaMd5Map)
|
||||
{
|
||||
string fileFullName = $"{fileName}.json";
|
||||
bool skip = false;
|
||||
|
||||
if (metadataContext.FileExists(fileFullName))
|
||||
{
|
||||
skip = md5 == await GetFileMd5Async(fileFullName, token)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
if (!skip)
|
||||
{
|
||||
logger.LogInformation("{file} 文件 MD5 不匹配", fileFullName);
|
||||
|
||||
await DownloadMetadataAsync(fileFullName, token)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DownloadMetadataAsync(string fileFullName, CancellationToken token)
|
||||
{
|
||||
Stream sourceStream = await httpClient
|
||||
.GetStreamAsync($"{MetaAPIHost}/{fileFullName}", token)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
// Write stream while convert LF to CRLF
|
||||
using (StreamReader streamReader = new(sourceStream))
|
||||
{
|
||||
using (StreamWriter streamWriter = new(metadataContext.Create(fileFullName)))
|
||||
{
|
||||
while (await streamReader.ReadLineAsync().ConfigureAwait(false) is string line)
|
||||
{
|
||||
await (streamReader.EndOfStream
|
||||
? streamWriter.WriteAsync(line) // Don't append the last line
|
||||
: streamWriter.WriteLineAsync(line))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.LogInformation("{file} 下载完成", fileFullName);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Service.Abstraction.Navigation;
|
||||
namespace Snap.Hutao.Service.Navigation;
|
||||
|
||||
/// <summary>
|
||||
/// 表示导航等待器
|
||||
@@ -1,8 +1,11 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Service.Abstraction.Navigation;
|
||||
namespace Snap.Hutao.Service.Navigation;
|
||||
|
||||
/// <summary>
|
||||
/// 为 <see cref="NavigationExtra"/> 提供抽象接口
|
||||
/// </summary>
|
||||
public interface INavigationExtra
|
||||
{
|
||||
/// <summary>
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Snap.Hutao.Service.Abstraction.Navigation;
|
||||
namespace Snap.Hutao.Service.Navigation;
|
||||
|
||||
/// <summary>
|
||||
/// 导航服务
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Service.Abstraction.Navigation;
|
||||
namespace Snap.Hutao.Service.Navigation;
|
||||
|
||||
/// <summary>
|
||||
/// 导航额外信息
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Service.Abstraction.Navigation;
|
||||
namespace Snap.Hutao.Service.Navigation;
|
||||
|
||||
/// <summary>
|
||||
/// 导航结果
|
||||
@@ -4,12 +4,11 @@
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Snap.Hutao.Core.Logging;
|
||||
using Snap.Hutao.Service.Abstraction;
|
||||
using Snap.Hutao.Service.Abstraction.Navigation;
|
||||
using Snap.Hutao.View.Helper;
|
||||
using Snap.Hutao.View.Page;
|
||||
using System.Linq;
|
||||
|
||||
namespace Snap.Hutao.Service;
|
||||
namespace Snap.Hutao.Service.Navigation;
|
||||
|
||||
/// <summary>
|
||||
/// 导航服务
|
||||
@@ -5,8 +5,8 @@
|
||||
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
|
||||
<RootNamespace>Snap.Hutao</RootNamespace>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
<Platforms>x86;x64;arm64</Platforms>
|
||||
<RuntimeIdentifiers>win10-x86;win10-x64;win10-arm64</RuntimeIdentifiers>
|
||||
<Platforms>x64</Platforms>
|
||||
<RuntimeIdentifiers>win10-x64</RuntimeIdentifiers>
|
||||
<PublishProfile>win10-$(Platform).pubxml</PublishProfile>
|
||||
<UseWinUI>true</UseWinUI>
|
||||
<ImplicitUsings>false</ImplicitUsings>
|
||||
@@ -31,9 +31,11 @@
|
||||
<None Remove="stylecop.json" />
|
||||
<None Remove="View\Dialog\UserDialog.xaml" />
|
||||
<None Remove="View\MainView.xaml" />
|
||||
<None Remove="View\Page\AchievementPage.xaml" />
|
||||
<None Remove="View\Page\AnnouncementContentPage.xaml" />
|
||||
<None Remove="View\Page\AnnouncementPage.xaml" />
|
||||
<None Remove="View\Page\SettingPage.xaml" />
|
||||
<None Remove="View\Page\WelcomePage.xaml" />
|
||||
<None Remove="View\TitleView.xaml" />
|
||||
<None Remove="View\UserView.xaml" />
|
||||
</ItemGroup>
|
||||
@@ -130,6 +132,16 @@
|
||||
<ProjectReference Include="..\SettingsUI\SettingsUI.csproj" />
|
||||
<ProjectReference Include="..\Snap.Hutao.SourceGeneration\Snap.Hutao.SourceGeneration.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="View\Page\AchievementPage.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="View\Page\WelcomePage.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="View\Dialog\UserDialog.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
||||
@@ -28,6 +28,12 @@
|
||||
</NavigationViewItem.Icon>
|
||||
</NavigationViewItem>
|
||||
|
||||
<NavigationViewItem Content="成就" helper:NavHelper.NavigateTo="page:AchievementPage">
|
||||
<NavigationViewItem.Icon>
|
||||
<FontIcon Glyph=""/>
|
||||
</NavigationViewItem.Icon>
|
||||
</NavigationViewItem>
|
||||
|
||||
</NavigationView.MenuItems>
|
||||
|
||||
<NavigationView.PaneFooter>
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Snap.Hutao.Service.Abstraction;
|
||||
using Snap.Hutao.Service.Abstraction.Navigation;
|
||||
using Snap.Hutao.Service.Navigation;
|
||||
using Snap.Hutao.View.Page;
|
||||
|
||||
namespace Snap.Hutao.View;
|
||||
|
||||
@@ -27,6 +28,6 @@ public sealed partial class MainView : UserControl
|
||||
|
||||
navigationService = Ioc.Default.GetRequiredService<INavigationService>();
|
||||
navigationService.Initialize(NavView, ContentFrame);
|
||||
navigationService.Navigate<Page.AnnouncementPage>(INavigationAwaiter.Default, true);
|
||||
navigationService.Navigate<WelcomePage>(INavigationAwaiter.Default, false);
|
||||
}
|
||||
}
|
||||
35
src/Snap.Hutao/Snap.Hutao/View/Page/AchievementPage.xaml
Normal file
35
src/Snap.Hutao/Snap.Hutao/View/Page/AchievementPage.xaml
Normal file
@@ -0,0 +1,35 @@
|
||||
<shcc:CancellablePage
|
||||
x:Class="Snap.Hutao.View.Page.AchievementPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Snap.Hutao.View.Page"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
xmlns:mxi="using:Microsoft.Xaml.Interactivity"
|
||||
xmlns:mxic="using:Microsoft.Xaml.Interactions.Core"
|
||||
xmlns:shcc="using:Snap.Hutao.Control.Cancellable"
|
||||
xmlns:settings="using:SettingsUI.Controls"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
<mxi:Interaction.Behaviors>
|
||||
<mxic:EventTriggerBehavior EventName="Loaded">
|
||||
<mxic:InvokeCommandAction Command="{Binding OpenUICommand}"/>
|
||||
</mxic:EventTriggerBehavior>
|
||||
</mxi:Interaction.Behaviors>
|
||||
<Grid>
|
||||
<ScrollViewer>
|
||||
<ItemsControl
|
||||
Margin="12,0,16,12"
|
||||
ItemsSource="{Binding AchievementsView}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<settings:Setting
|
||||
Margin="0,12,0,0"
|
||||
Header="{Binding Title}"
|
||||
Description="{Binding Description}"/>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</shcc:CancellablePage>
|
||||
22
src/Snap.Hutao/Snap.Hutao/View/Page/AchievementPage.xaml.cs
Normal file
22
src/Snap.Hutao/Snap.Hutao/View/Page/AchievementPage.xaml.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Control.Cancellable;
|
||||
using Snap.Hutao.ViewModel;
|
||||
|
||||
namespace Snap.Hutao.View.Page;
|
||||
|
||||
/// <summary>
|
||||
/// 成就页面
|
||||
/// </summary>
|
||||
public sealed partial class AchievementPage : CancellablePage
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造一个新的成就页面
|
||||
/// </summary>
|
||||
public AchievementPage()
|
||||
{
|
||||
InitializeWith<AchievementViewModel>();
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,8 @@
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
using Microsoft.VisualStudio.Threading;
|
||||
using Snap.Hutao.Core;
|
||||
using Snap.Hutao.Service.Abstraction.Navigation;
|
||||
using Snap.Hutao.Extension;
|
||||
using Snap.Hutao.Service.Navigation;
|
||||
|
||||
namespace Snap.Hutao.View.Page;
|
||||
|
||||
@@ -38,7 +39,7 @@ openInWebview: function(url){ location.href = url }}";
|
||||
if (e.Parameter is INavigationExtra extra)
|
||||
{
|
||||
targetContent = extra.Data as string;
|
||||
LoadAnnouncementAsync(extra).Forget();
|
||||
LoadAnnouncementAsync(extra).SafeForget();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,4 +61,4 @@ openInWebview: function(url){ location.href = url }}";
|
||||
WebView.NavigateToString(targetContent);
|
||||
extra.NotifyNavigationCompleted();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,9 +43,9 @@
|
||||
Margin="0,0,0,12"
|
||||
Style="{StaticResource TitleTextBlockStyle}"/>
|
||||
<cwucont:AdaptiveGridView
|
||||
cwua:ItemsReorderAnimation.Duration="0:0:0.06"
|
||||
cwua:ItemsReorderAnimation.Duration="0:0:0.1"
|
||||
SelectionMode="None"
|
||||
DesiredWidth="280"
|
||||
DesiredWidth="300"
|
||||
HorizontalAlignment="Stretch"
|
||||
ItemsSource="{Binding List}"
|
||||
Margin="0,0,2,0">
|
||||
|
||||
@@ -16,7 +16,7 @@ public sealed partial class AnnouncementPage : CancellablePage
|
||||
/// </summary>
|
||||
public AnnouncementPage()
|
||||
{
|
||||
Initialize(Ioc.Default.GetRequiredService<AnnouncementViewModel>());
|
||||
InitializeWith<AnnouncementViewModel>();
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
|
||||
16
src/Snap.Hutao/Snap.Hutao/View/Page/WelcomePage.xaml
Normal file
16
src/Snap.Hutao/Snap.Hutao/View/Page/WelcomePage.xaml
Normal file
@@ -0,0 +1,16 @@
|
||||
<Page
|
||||
x:Class="Snap.Hutao.View.Page.WelcomePage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Snap.Hutao.View.Page"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
|
||||
<Grid Padding="12">
|
||||
<TextBlock
|
||||
Text="欢迎使用胡桃"
|
||||
Style="{StaticResource TitleTextBlockStyle}"/>
|
||||
</Grid>
|
||||
</Page>
|
||||
18
src/Snap.Hutao/Snap.Hutao/View/Page/WelcomePage.xaml.cs
Normal file
18
src/Snap.Hutao/Snap.Hutao/View/Page/WelcomePage.xaml.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.View.Page;
|
||||
|
||||
/// <summary>
|
||||
/// 欢迎页
|
||||
/// </summary>
|
||||
public sealed partial class WelcomePage : Microsoft.UI.Xaml.Controls.Page
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造一个新的欢迎页
|
||||
/// </summary>
|
||||
public WelcomePage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
66
src/Snap.Hutao/Snap.Hutao/ViewModel/AchievementViewModel.cs
Normal file
66
src/Snap.Hutao/Snap.Hutao/ViewModel/AchievementViewModel.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.WinUI.UI;
|
||||
using Microsoft.VisualStudio.Threading;
|
||||
using Snap.Hutao.Control.Cancellable;
|
||||
using Snap.Hutao.Factory.Abstraction;
|
||||
using Snap.Hutao.Model.Metadata.Achievement;
|
||||
using Snap.Hutao.Service.Metadata;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Snap.Hutao.ViewModel;
|
||||
|
||||
/// <summary>
|
||||
/// 成就视图模型
|
||||
/// </summary>
|
||||
[Injection(InjectAs.Transient)]
|
||||
internal class AchievementViewModel : ObservableObject, ISupportCancellation
|
||||
{
|
||||
private readonly IMetadataService metadataService;
|
||||
private AdvancedCollectionView? achievementsView;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的成就视图模型
|
||||
/// </summary>
|
||||
/// <param name="metadataService">元数据服务</param>
|
||||
/// <param name="asyncRelayCommandFactory">异步命令工厂</param>
|
||||
public AchievementViewModel(IMetadataService metadataService, IAsyncRelayCommandFactory asyncRelayCommandFactory)
|
||||
{
|
||||
this.metadataService = metadataService;
|
||||
OpenUICommand = asyncRelayCommandFactory.Create(OpenUIAsync);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public CancellationToken CancellationToken { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 成就视图
|
||||
/// </summary>
|
||||
public AdvancedCollectionView? AchievementsView
|
||||
{
|
||||
get => achievementsView;
|
||||
set => SetProperty(ref achievementsView, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 打开页面命令
|
||||
/// </summary>
|
||||
public ICommand OpenUICommand { get; }
|
||||
|
||||
private async Task OpenUIAsync(CancellationToken token)
|
||||
{
|
||||
using (CancellationTokenExtensions.CombinedCancellationToken combined = token.CombineWith(CancellationToken))
|
||||
{
|
||||
if (await metadataService.InitializeAsync(combined.Token))
|
||||
{
|
||||
IEnumerable<Achievement> achievements = await metadataService.GetAchievementsAsync(combined.Token);
|
||||
|
||||
// TODO
|
||||
AchievementsView = new(achievements.ToList());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,8 @@ using Snap.Hutao.Core;
|
||||
using Snap.Hutao.Core.Threading;
|
||||
using Snap.Hutao.Factory.Abstraction;
|
||||
using Snap.Hutao.Service.Abstraction;
|
||||
using Snap.Hutao.Service.Abstraction.Navigation;
|
||||
using Snap.Hutao.Service.Navigation;
|
||||
using Snap.Hutao.View.Page;
|
||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Common.Announcement;
|
||||
|
||||
namespace Snap.Hutao.ViewModel;
|
||||
@@ -99,7 +100,7 @@ internal class AnnouncementViewModel : ObservableObject, ISupportCancellation
|
||||
|
||||
if (WebView2Helper.IsSupported)
|
||||
{
|
||||
navigationService.Navigate<View.Page.AnnouncementContentPage>(data: new NavigationExtra(content));
|
||||
navigationService.Navigate<AnnouncementContentPage>(data: new NavigationExtra(content));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
40
src/Snap.Hutao/Snap.Hutao/Web/Enka/EnkaClient.cs
Normal file
40
src/Snap.Hutao/Snap.Hutao/Web/Enka/EnkaClient.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Web.Enka.Model;
|
||||
using Snap.Hutao.Web.Hoyolab;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
|
||||
namespace Snap.Hutao.Web.Enka;
|
||||
|
||||
/// <summary>
|
||||
/// Enka API 客户端
|
||||
/// </summary>
|
||||
[Injection(InjectAs.Transient)]
|
||||
internal class EnkaClient
|
||||
{
|
||||
private const string EnkaAPI = "https://enka.shinshin.moe/u/{0}/__data.json";
|
||||
|
||||
private readonly HttpClient httpClient;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的 Enka API 客户端
|
||||
/// </summary>
|
||||
/// <param name="httpClient">http客户端</param>
|
||||
public EnkaClient(HttpClient httpClient)
|
||||
{
|
||||
this.httpClient = httpClient;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步获取 Enka API 响应
|
||||
/// </summary>
|
||||
/// <param name="playerUid">玩家Uid</param>
|
||||
/// <param name="token">取消令牌</param>
|
||||
/// <returns>Enka API 响应</returns>
|
||||
public Task<EnkaResponse?> GetDataAsync(PlayerUid playerUid, CancellationToken token)
|
||||
{
|
||||
return httpClient.GetFromJsonAsync<EnkaResponse>(string.Format(EnkaAPI, playerUid.Value), token);
|
||||
}
|
||||
}
|
||||
92
src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/AvatarInfo.cs
Normal file
92
src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/AvatarInfo.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.Json.Converter;
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Snap.Hutao.Web.Enka.Model;
|
||||
|
||||
/// <summary>
|
||||
/// 角色信息
|
||||
/// </summary>
|
||||
public class AvatarInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 角色Id
|
||||
/// Character ID
|
||||
/// </summary>
|
||||
[JsonPropertyName("avatarId")]
|
||||
public int AvatarId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 基础属性
|
||||
/// Character Info Properties List
|
||||
/// <see cref="PlayerProperty.PROP_EXP"/>
|
||||
/// </summary>
|
||||
[JsonPropertyName("propMap")]
|
||||
[JsonConverter(typeof(StringEnumKeyDictionaryConverter))]
|
||||
public IDictionary<PlayerProperty, TypeValue> PropMap { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 命座 Id
|
||||
/// </summary>
|
||||
[JsonPropertyName("talentIdList")]
|
||||
public IList<int> TalentIdList { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 属性Map
|
||||
/// Map of Character's Combat Properties.
|
||||
/// </summary>
|
||||
[JsonPropertyName("fightPropMap")]
|
||||
[JsonConverter(typeof(StringEnumKeyDictionaryConverter))]
|
||||
public IDictionary<FightProperty, double> FightPropMap { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 技能组Id
|
||||
/// Character Skill Set ID
|
||||
/// </summary>
|
||||
[JsonPropertyName("skillDepotId")]
|
||||
public int SkillDepotId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of Unlocked Skill Ids
|
||||
/// 被动天赋
|
||||
/// </summary>
|
||||
[JsonPropertyName("inherentProudSkillList")]
|
||||
public IList<int> InherentProudSkillList { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Map of Skill Levels
|
||||
/// </summary>
|
||||
[JsonPropertyName("skillLevelMap")]
|
||||
public IDictionary<string, int> SkillLevelMap { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 装备列表
|
||||
/// 最后一个为武器
|
||||
/// List of Equipments: Weapon, Ariftacts
|
||||
/// </summary>
|
||||
[JsonPropertyName("equipList")]
|
||||
public IList<Equip> EquipList { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 好感度信息
|
||||
/// Character Friendship Level
|
||||
/// </summary>
|
||||
[JsonPropertyName("fetterInfo")]
|
||||
public FetterInfo FetterInfo { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 皮肤 Id
|
||||
/// </summary>
|
||||
[JsonPropertyName("costumeId")]
|
||||
public int? CostumeId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 命座额外技能等级
|
||||
/// </summary>
|
||||
[JsonPropertyName("proudSkillExtraLevelMap")]
|
||||
public IDictionary<string, int> ProudSkillExtraLevelMap { get; set; } = default!;
|
||||
}
|
||||
48
src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/EnkaResponse.cs
Normal file
48
src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/EnkaResponse.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Snap.Hutao.Web.Enka.Model;
|
||||
|
||||
/// <summary>
|
||||
/// Enka API 响应
|
||||
/// </summary>
|
||||
public class EnkaResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// 玩家基础信息
|
||||
/// </summary>
|
||||
[JsonPropertyName("playerInfo")]
|
||||
public PlayerInfo? PlayerInfo { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 展示的角色详细信息列表
|
||||
/// </summary>
|
||||
[JsonPropertyName("avatarInfoList")]
|
||||
public IList<AvatarInfo>? AvatarInfoList { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 刷新剩余秒数
|
||||
/// 生存时间值
|
||||
/// </summary>
|
||||
[JsonPropertyName("ttl")]
|
||||
public int? Ttl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 此响应是否有效
|
||||
/// </summary>
|
||||
public bool IsValid
|
||||
{
|
||||
get => Ttl.HasValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否包含角色详细数据
|
||||
/// </summary>
|
||||
public bool HasDetail
|
||||
{
|
||||
get => AvatarInfoList != null;
|
||||
}
|
||||
}
|
||||
39
src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/Equip.cs
Normal file
39
src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/Equip.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Snap.Hutao.Web.Enka.Model;
|
||||
|
||||
/// <summary>
|
||||
/// 装备
|
||||
/// </summary>
|
||||
public class Equip
|
||||
{
|
||||
/// <summary>
|
||||
/// 物品Id
|
||||
/// Equipment ID
|
||||
/// </summary>
|
||||
[JsonPropertyName("itemId")]
|
||||
public int ItemId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 圣遗物
|
||||
/// Artifact Base Info
|
||||
/// </summary>
|
||||
[JsonPropertyName("reliquary")]
|
||||
public Reliquary? Reliquary { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 武器
|
||||
/// Weapon Base Info
|
||||
/// </summary>
|
||||
[JsonPropertyName("weapon")]
|
||||
public Weapon? Weapon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Detailed Info of Equipment
|
||||
/// </summary>
|
||||
[JsonPropertyName("flat")]
|
||||
public Flat Flat { get; set; } = default!;
|
||||
}
|
||||
18
src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/FetterInfo.cs
Normal file
18
src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/FetterInfo.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Snap.Hutao.Web.Enka.Model;
|
||||
|
||||
/// <summary>
|
||||
/// 好感度信息
|
||||
/// </summary>
|
||||
public class FetterInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 好感度等级
|
||||
/// </summary>
|
||||
[JsonPropertyName("expLevel")]
|
||||
public int ExpLevel { get; set; }
|
||||
}
|
||||
84
src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/Flat.cs
Normal file
84
src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/Flat.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Snap.Hutao.Web.Enka.Model;
|
||||
|
||||
/// <summary>
|
||||
/// 平展值
|
||||
/// </summary>
|
||||
public class Flat
|
||||
{
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// Hash for Equipment Name
|
||||
/// </summary>
|
||||
[JsonPropertyName("nameTextMapHash")]
|
||||
public string NameTextMapHash { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 套装名称
|
||||
/// Hash for Artifact Set Name
|
||||
/// </summary>
|
||||
[JsonPropertyName("setNameTextMapHash")]
|
||||
public string? SetNameTextMapHash { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 等级
|
||||
/// Rarity Level of Equipment
|
||||
/// </summary>
|
||||
[JsonPropertyName("rankLevel")]
|
||||
public int RankLevel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 圣遗物主属性
|
||||
/// Artifact Main Stat
|
||||
/// </summary>
|
||||
[JsonPropertyName("reliquaryMainstat")]
|
||||
public ReliquaryMainstat? ReliquaryMainstat { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 圣遗物副属性
|
||||
/// List of Artifact Substats
|
||||
/// </summary>
|
||||
[JsonPropertyName("reliquarySubstats")]
|
||||
public IList<ReliquarySubstat>? ReliquarySubstats { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 物品类型
|
||||
/// Equipment Type: Weapon or Artifact
|
||||
/// ITEM_WEAPON
|
||||
/// ITEM_RELIQUARY
|
||||
/// </summary>
|
||||
[JsonPropertyName("itemType")]
|
||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||
public ItemType ItemType { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 图标
|
||||
/// Equipment Icon Name
|
||||
/// </summary>
|
||||
[JsonPropertyName("icon")]
|
||||
public string Icon { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 圣遗物类型
|
||||
/// 当为武器时
|
||||
/// 值为 <see cref="EquipType.EQUIP_NONE"/>
|
||||
/// </summary>
|
||||
[JsonPropertyName("equipType")]
|
||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||
public EquipType EquipType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 武器主副属性
|
||||
/// 0 基础攻击力
|
||||
/// 1 主属性
|
||||
/// List of Weapon Stat: Base ATK, Substat
|
||||
/// </summary>
|
||||
[JsonPropertyName("weaponStats")]
|
||||
public IList<WeaponStat>? WeaponStats { get; set; }
|
||||
}
|
||||
89
src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/PlayerInfo.cs
Normal file
89
src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/PlayerInfo.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Snap.Hutao.Web.Enka.Model;
|
||||
|
||||
/// <summary>
|
||||
/// 玩家信息
|
||||
/// </summary>
|
||||
public class PlayerInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 昵称
|
||||
/// Player Nickname
|
||||
/// </summary>
|
||||
[JsonPropertyName("nickname")]
|
||||
public string Nickname { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 等级
|
||||
/// </summary>
|
||||
[JsonPropertyName("level")]
|
||||
public int Level { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 签名
|
||||
/// Profile Signature
|
||||
/// </summary>
|
||||
[JsonPropertyName("signature")]
|
||||
public string Signature { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 世界等级
|
||||
/// Player World Level
|
||||
/// </summary>
|
||||
[JsonPropertyName("worldLevel")]
|
||||
public int WorldLevel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 名片的Id
|
||||
/// Profile Namecard ID
|
||||
/// </summary>
|
||||
[JsonPropertyName("nameCardId")]
|
||||
public int NameCardId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 完成的成就个数
|
||||
/// Number of Completed Achievements
|
||||
/// </summary>
|
||||
[JsonPropertyName("finishAchievementNum")]
|
||||
public int FinishAchievementNum { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 深渊层数
|
||||
/// Abyss Floor
|
||||
/// </summary>
|
||||
[JsonPropertyName("towerFloorIndex")]
|
||||
public int TowerFloorIndex { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 深渊间数
|
||||
/// Abyss Floor's Level
|
||||
/// </summary>
|
||||
[JsonPropertyName("towerLevelIndex")]
|
||||
public int TowerLevelIndex { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 展示的角色信息
|
||||
/// List of Character IDs and Levels
|
||||
/// </summary>
|
||||
[JsonPropertyName("showAvatarInfoList")]
|
||||
public IList<ShowAvatarInfo> ShowAvatarInfoList { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 展示的名片信息
|
||||
/// List of Namecard IDs
|
||||
/// </summary>
|
||||
[JsonPropertyName("showNameCardIdList")]
|
||||
public IList<int> ShowNameCardIdList { get; set; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// 头像信息
|
||||
/// Character ID of Profile Picture
|
||||
/// </summary>
|
||||
[JsonPropertyName("profilePicture")]
|
||||
public ProfilePicture ProfilePicture { get; set; } = default!;
|
||||
}
|
||||
228
src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/PlayerProperty.cs
Normal file
228
src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/PlayerProperty.cs
Normal file
@@ -0,0 +1,228 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Enka.Model;
|
||||
|
||||
/// <summary>
|
||||
/// 玩家属性
|
||||
/// https://github.com/Grasscutters/Grasscutter/tree/development/src/main/java/emu/grasscutter/game/props/PlayerProperty.java
|
||||
/// </summary>
|
||||
public enum PlayerProperty
|
||||
{
|
||||
/// <summary>
|
||||
/// 空
|
||||
/// </summary>
|
||||
PROP_NONE = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 经验值
|
||||
/// </summary>
|
||||
PROP_EXP = 1001,
|
||||
|
||||
/// <summary>
|
||||
/// 突破等级
|
||||
/// </summary>
|
||||
PROP_BREAK_LEVEL = 1002,
|
||||
|
||||
/// <summary>
|
||||
/// 饱食度
|
||||
/// </summary>
|
||||
PROP_SATIATION_VAL = 1003,
|
||||
|
||||
/// <summary>
|
||||
/// 饱食度冷却
|
||||
/// </summary>
|
||||
PROP_SATIATION_PENALTY_TIME = 1004,
|
||||
|
||||
/// <summary>
|
||||
/// 等级
|
||||
/// </summary>
|
||||
PROP_LEVEL = 4001,
|
||||
|
||||
/// <summary>
|
||||
/// 上次切换角色的时间
|
||||
/// </summary>
|
||||
PROP_LAST_CHANGE_AVATAR_TIME = 10001,
|
||||
|
||||
/// <summary>
|
||||
/// Maximum volume of the Statue of the Seven for the player [0, 8500000]
|
||||
/// </summary>
|
||||
PROP_MAX_SPRING_VOLUME = 10002,
|
||||
|
||||
/// <summary>
|
||||
/// Current volume of the Statue of the Seven [0, PROP_MAX_SPRING_VOLUME]
|
||||
/// </summary>
|
||||
PROP_CUR_SPRING_VOLUME = 10003,
|
||||
|
||||
/// <summary>
|
||||
/// Auto HP recovery when approaching the Statue of the Seven [0, 1]
|
||||
/// </summary>
|
||||
PROP_IS_SPRING_AUTO_USE = 10004,
|
||||
|
||||
/// <summary>
|
||||
/// Auto HP recovery percentage [0, 100]
|
||||
/// </summary>
|
||||
PROP_SPRING_AUTO_USE_PERCENT = 10005,
|
||||
|
||||
/// <summary>
|
||||
/// Are you in a state that disables your flying ability? e.g. new player [0, 1]
|
||||
/// </summary>
|
||||
PROP_IS_FLYABLE = 10006,
|
||||
|
||||
/// <summary>
|
||||
/// 天气是否锁定
|
||||
/// </summary>
|
||||
PROP_IS_WEATHER_LOCKED = 10007,
|
||||
|
||||
/// <summary>
|
||||
/// 游戏时间是否锁定
|
||||
/// </summary>
|
||||
PROP_IS_GAME_TIME_LOCKED = 10008,
|
||||
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// </summary>
|
||||
PROP_IS_TRANSFERABLE = 10009,
|
||||
|
||||
/// <summary>
|
||||
/// Maximum stamina of the player =0 - 24000
|
||||
/// </summary>
|
||||
PROP_MAX_STAMINA = 10010,
|
||||
|
||||
/// <summary>
|
||||
/// Used stamina of the player =0 - PROP_MAX_STAMINA
|
||||
/// </summary>
|
||||
PROP_CUR_PERSIST_STAMINA = 10011,
|
||||
|
||||
/// <summary>
|
||||
/// 临时体力,食物?
|
||||
/// </summary>
|
||||
PROP_CUR_TEMPORARY_STAMINA = 10012,
|
||||
|
||||
/// <summary>
|
||||
/// 玩家等级
|
||||
/// </summary>
|
||||
PROP_PLAYER_LEVEL = 10013,
|
||||
|
||||
/// <summary>
|
||||
/// 玩家经验
|
||||
/// </summary>
|
||||
PROP_PLAYER_EXP = 10014,
|
||||
|
||||
/// <summary>
|
||||
/// Primogem =-inf, +inf
|
||||
/// It is known that Mihoyo will make Primogem negative in the cases that a player spends
|
||||
/// his gems and then got a money refund, so negative is allowed.
|
||||
/// </summary>
|
||||
PROP_PLAYER_HCOIN = 10015,
|
||||
|
||||
/// <summary>
|
||||
/// Mora [0, +inf
|
||||
/// </summary>
|
||||
PROP_PLAYER_SCOIN = 10016,
|
||||
|
||||
/// <summary>
|
||||
/// Do you allow other players to join your game? [0=no 1=direct 2=approval]
|
||||
/// </summary>
|
||||
PROP_PLAYER_MP_SETTING_TYPE = 10017,
|
||||
|
||||
/// <summary>
|
||||
/// 0 if in quest or something that disables MP [0, 1]
|
||||
/// </summary>
|
||||
PROP_IS_MP_MODE_AVAILABLE = 10018,
|
||||
|
||||
/// <summary>
|
||||
/// [0, 8]
|
||||
/// </summary>
|
||||
PROP_PLAYER_WORLD_LEVEL = 10019,
|
||||
|
||||
/// <summary>
|
||||
/// Original Resin [0, 2000] - note that values above 160 require refills
|
||||
/// </summary>
|
||||
PROP_PLAYER_RESIN = 10020,
|
||||
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// </summary>
|
||||
PROP_PLAYER_WAIT_SUB_HCOIN = 10022,
|
||||
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// </summary>
|
||||
PROP_PLAYER_WAIT_SUB_SCOIN = 10023,
|
||||
|
||||
/// <summary>
|
||||
/// Is only MP with PlayStation players? [0, 1]
|
||||
/// </summary>
|
||||
PROP_IS_ONLY_MP_WITH_PS_PLAYER = 10024,
|
||||
|
||||
/// <summary>
|
||||
/// Genesis Crystal =-inf, +inf see 10015
|
||||
/// </summary>
|
||||
PROP_PLAYER_MCOIN = 10025,
|
||||
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// </summary>
|
||||
PROP_PLAYER_WAIT_SUB_MCOIN = 10026,
|
||||
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// </summary>
|
||||
PROP_PLAYER_LEGENDARY_KEY = 10027,
|
||||
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// </summary>
|
||||
PROP_IS_HAS_FIRST_SHARE = 10028,
|
||||
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// </summary>
|
||||
PROP_PLAYER_FORGE_POINT = 10029,
|
||||
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// </summary>
|
||||
PROP_CUR_CLIMATE_METER = 10035,
|
||||
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// </summary>
|
||||
PROP_CUR_CLIMATE_TYPE = 10036,
|
||||
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// </summary>
|
||||
PROP_CUR_CLIMATE_AREA_ID = 10037,
|
||||
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// </summary>
|
||||
PROP_CUR_CLIMATE_AREA_CLIMATE_TYPE = 10038,
|
||||
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// </summary>
|
||||
PROP_PLAYER_WORLD_LEVEL_LIMIT = 10039,
|
||||
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// </summary>
|
||||
PROP_PLAYER_WORLD_LEVEL_ADJUST_CD = 10040,
|
||||
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// </summary>
|
||||
PROP_PLAYER_LEGENDARY_DAILY_TASK_NUM = 10041,
|
||||
|
||||
/// <summary>
|
||||
/// Realm currency [0, +inf
|
||||
/// </summary>
|
||||
PROP_PLAYER_HOME_COIN = 10042,
|
||||
|
||||
/// <summary>
|
||||
/// ?
|
||||
/// </summary>
|
||||
PROP_PLAYER_WAIT_SUB_HOME_COIN = 10043,
|
||||
}
|
||||
18
src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/ProfilePicture.cs
Normal file
18
src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/ProfilePicture.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Snap.Hutao.Web.Enka.Model;
|
||||
|
||||
/// <summary>
|
||||
/// 档案头像
|
||||
/// </summary>
|
||||
public class ProfilePicture
|
||||
{
|
||||
/// <summary>
|
||||
/// 使用的角色Id
|
||||
/// </summary>
|
||||
[JsonPropertyName("avatarId")]
|
||||
public int AvatarId { get; set; }
|
||||
}
|
||||
34
src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/Reliquary.cs
Normal file
34
src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/Reliquary.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Snap.Hutao.Web.Enka.Model;
|
||||
|
||||
/// <summary>
|
||||
/// 圣遗物
|
||||
/// </summary>
|
||||
public class Reliquary
|
||||
{
|
||||
/// <summary>
|
||||
/// 等级 +20 = 21
|
||||
/// [1,21]
|
||||
/// Artifact Level [1-21]
|
||||
/// </summary>
|
||||
[JsonPropertyName("level")]
|
||||
public int Level { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 主属性Id
|
||||
/// Artifact Main Stat ID
|
||||
/// </summary>
|
||||
[JsonPropertyName("mainPropId")]
|
||||
public int MainPropId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 强化属性Id
|
||||
/// </summary>
|
||||
[JsonPropertyName("appendPropIdList")]
|
||||
public IList<int> AppendPropIdList { get; set; } = default!;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Snap.Hutao.Web.Enka.Model;
|
||||
|
||||
/// <summary>
|
||||
/// 圣遗物主属性
|
||||
/// </summary>
|
||||
public class ReliquaryMainstat
|
||||
{
|
||||
/// <summary>
|
||||
/// Equipment Append Property Name.
|
||||
/// </summary>
|
||||
[JsonPropertyName("mainPropId")]
|
||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||
public FightProperty MainPropId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Property Value
|
||||
/// </summary>
|
||||
[JsonPropertyName("statValue")]
|
||||
public double StatValue { get; set; }
|
||||
}
|
||||
26
src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/ReliquarySubstat.cs
Normal file
26
src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/ReliquarySubstat.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Snap.Hutao.Web.Enka.Model;
|
||||
|
||||
/// <summary>
|
||||
/// 圣遗物副属性
|
||||
/// </summary>
|
||||
public class ReliquarySubstat
|
||||
{
|
||||
/// <summary>
|
||||
/// 增加属性
|
||||
/// </summary>
|
||||
[JsonPropertyName("appendPropId")]
|
||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||
public FightProperty AppendPropId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 值
|
||||
/// </summary>
|
||||
[JsonPropertyName("statValue")]
|
||||
public double StatValue { get; set; }
|
||||
}
|
||||
32
src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/ShowAvatarInfo.cs
Normal file
32
src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/ShowAvatarInfo.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Snap.Hutao.Web.Enka.Model;
|
||||
|
||||
/// <summary>
|
||||
/// 角色列表信息
|
||||
/// </summary>
|
||||
public class ShowAvatarInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 角色Id
|
||||
/// Character ID
|
||||
/// </summary>
|
||||
[JsonPropertyName("avatarId")]
|
||||
public int AvatarId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 角色等级
|
||||
/// Character Level
|
||||
/// </summary>
|
||||
[JsonPropertyName("level")]
|
||||
public int Level { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 可能的皮肤Id
|
||||
/// </summary>
|
||||
[JsonPropertyName("costumeId")]
|
||||
public int? CostumeId { get; set; }
|
||||
}
|
||||
24
src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/TypeValue.cs
Normal file
24
src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/TypeValue.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Snap.Hutao.Web.Enka.Model;
|
||||
|
||||
/// <summary>
|
||||
/// 类型与值
|
||||
/// </summary>
|
||||
public class TypeValue
|
||||
{
|
||||
/// <summary>
|
||||
/// 类型
|
||||
/// </summary>
|
||||
[JsonPropertyName("type")]
|
||||
public PlayerProperty Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 值
|
||||
/// </summary>
|
||||
[JsonPropertyName("val")]
|
||||
public string? Value { get; set; }
|
||||
}
|
||||
34
src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/Weapon.cs
Normal file
34
src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/Weapon.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Snap.Hutao.Web.Enka.Model;
|
||||
|
||||
/// <summary>
|
||||
/// 武器信息
|
||||
/// </summary>
|
||||
public class Weapon
|
||||
{
|
||||
/// <summary>
|
||||
/// 等级
|
||||
/// Weapon Level
|
||||
/// </summary>
|
||||
[JsonPropertyName("level")]
|
||||
public int Level { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 突破等级
|
||||
/// Weapon Ascension Level
|
||||
/// </summary>
|
||||
[JsonPropertyName("promoteLevel")]
|
||||
public int PromoteLevel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 精炼 相较于实际等级 -1
|
||||
/// Weapon Refinement Level [0-4]
|
||||
/// </summary>
|
||||
[JsonPropertyName("affixMap")]
|
||||
public IDictionary<string, int> AffixMap { get; set; } = default!;
|
||||
}
|
||||
26
src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/WeaponStat.cs
Normal file
26
src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/WeaponStat.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Snap.Hutao.Web.Enka.Model;
|
||||
|
||||
/// <summary>
|
||||
/// 武器属性
|
||||
/// </summary>
|
||||
public class WeaponStat
|
||||
{
|
||||
/// <summary>
|
||||
/// 提升属性Id
|
||||
/// </summary>
|
||||
[JsonPropertyName("appendPropId")]
|
||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||
public FightProperty AppendPropId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 值
|
||||
/// </summary>
|
||||
[JsonPropertyName("statValue")]
|
||||
public double StatValue { get; set; }
|
||||
}
|
||||
@@ -2,7 +2,6 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.Bbs.User;
|
||||
|
||||
@@ -5,7 +5,6 @@ using Snap.Hutao.Web.Hoyolab.DynamicSecret;
|
||||
using Snap.Hutao.Web.Response;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.Bbs.User;
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.Bbs.User;
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
using Snap.Hutao.Core.Convertion;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.DynamicSecret;
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
using Snap.Hutao.Extension;
|
||||
using System.Net.Http;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.DynamicSecret;
|
||||
|
||||
|
||||
@@ -6,8 +6,6 @@ using Snap.Hutao.Web.Response;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.Hk4e.Common.Announcement;
|
||||
|
||||
@@ -52,8 +50,7 @@ internal class AnnouncementClient
|
||||
/// <returns>公告内容列表</returns>
|
||||
public async Task<List<AnnouncementContent>> GetAnnouncementContentsAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||
|
||||
// Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||
Response<ListWrapper<AnnouncementContent>>? resp = await httpClient
|
||||
.GetFromJsonAsync<Response<ListWrapper<AnnouncementContent>>>(ApiEndpoints.AnnContent, jsonSerializerOptions, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.Takumi;
|
||||
namespace Snap.Hutao.Web.Hoyolab;
|
||||
|
||||
/// <summary>
|
||||
/// 玩家 Uid
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Avatar;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user