mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
76800de6ee | ||
|
|
72b660119f | ||
|
|
67a1d5dc74 | ||
|
|
6e6d125814 |
@@ -24,7 +24,7 @@ internal class I18NExtension : MarkupExtension
|
|||||||
static I18NExtension()
|
static I18NExtension()
|
||||||
{
|
{
|
||||||
string currentName = CultureInfo.CurrentUICulture.Name;
|
string currentName = CultureInfo.CurrentUICulture.Name;
|
||||||
Type? languageType = ((IDictionary<string, Type>)TranslationMap).GetValueOrDefault2(currentName, typeof(LanguagezhCN));
|
Type? languageType = TranslationMap.GetValueOrDefault2(currentName, typeof(LanguagezhCN));
|
||||||
Translation = (ITranslation)Activator.CreateInstance(languageType!)!;
|
Translation = (ITranslation)Activator.CreateInstance(languageType!)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Microsoft.UI.Xaml.Controls;
|
|
||||||
using Microsoft.UI.Xaml.Markup;
|
using Microsoft.UI.Xaml.Markup;
|
||||||
|
|
||||||
namespace Snap.Hutao.Control.Markup;
|
namespace Snap.Hutao.Control.Markup;
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
using Microsoft.UI.Xaml.Controls;
|
using Microsoft.UI.Xaml.Controls;
|
||||||
using Snap.Hutao.Core;
|
using Snap.Hutao.Core;
|
||||||
using Snap.Hutao.Web.Hutao.Model;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Control.Panel;
|
namespace Snap.Hutao.Control.Panel;
|
||||||
|
|
||||||
@@ -28,8 +27,8 @@ public sealed partial class PanelSelector : UserControl
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string Current
|
public string Current
|
||||||
{
|
{
|
||||||
get { return (string)GetValue(CurrentProperty); }
|
get => (string)GetValue(CurrentProperty);
|
||||||
set { SetValue(CurrentProperty, value); }
|
set => SetValue(CurrentProperty, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SplitButtonLoaded(object sender, RoutedEventArgs e)
|
private void SplitButtonLoaded(object sender, RoutedEventArgs e)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
// See the LICENSE file in the project root for more information.
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
using Snap.Hutao.Core.Logging;
|
using Snap.Hutao.Core.Logging;
|
||||||
using Snap.Hutao.Extension;
|
using Snap.Hutao.Core.Threading;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ internal static class CoreEnvironment
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 动态密钥1的盐
|
/// 动态密钥1的盐
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const string DynamicSecret1Salt = "Qqx8cyv7kuyD8fTw11SmvXSFHp7iZD29";
|
public const string DynamicSecret1Salt = "yUZ3s0Sna1IrSNfk29Vo6vRapdOyqyhB";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 动态密钥2的盐
|
/// 动态密钥2的盐
|
||||||
@@ -32,7 +32,7 @@ internal static class CoreEnvironment
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 米游社 Rpc 版本
|
/// 米游社 Rpc 版本
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const string HoyolabXrpcVersion = "2.37.1";
|
public const string HoyolabXrpcVersion = "2.38.1";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 标准UA
|
/// 标准UA
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ internal static partial class IocHttpClientConfiguration
|
|||||||
{
|
{
|
||||||
client.Timeout = Timeout.InfiniteTimeSpan;
|
client.Timeout = Timeout.InfiniteTimeSpan;
|
||||||
client.DefaultRequestHeaders.UserAgent.ParseAdd(CoreEnvironment.HoyolabUA);
|
client.DefaultRequestHeaders.UserAgent.ParseAdd(CoreEnvironment.HoyolabUA);
|
||||||
|
client.DefaultRequestHeaders.Accept.ParseAdd("application/json");
|
||||||
client.DefaultRequestHeaders.Add("x-rpc-app_version", CoreEnvironment.HoyolabXrpcVersion);
|
client.DefaultRequestHeaders.Add("x-rpc-app_version", CoreEnvironment.HoyolabXrpcVersion);
|
||||||
client.DefaultRequestHeaders.Add("x-rpc-client_type", "5");
|
client.DefaultRequestHeaders.Add("x-rpc-client_type", "5");
|
||||||
client.DefaultRequestHeaders.Add("x-rpc-device_id", CoreEnvironment.HoyolabDeviceId);
|
client.DefaultRequestHeaders.Add("x-rpc-device_id", CoreEnvironment.HoyolabDeviceId);
|
||||||
|
|||||||
@@ -2,10 +2,7 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
using Snap.Hutao.Core.Diagnostics;
|
|
||||||
using Snap.Hutao.Core.Logging;
|
using Snap.Hutao.Core.Logging;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Core.Exception;
|
namespace Snap.Hutao.Core.Exception;
|
||||||
|
|
||||||
|
|||||||
30
src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniComment.cs
Normal file
30
src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniComment.cs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Core.IO.Ini;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ini 注释
|
||||||
|
/// </summary>
|
||||||
|
internal class IniComment : IniElement
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 构造一个新的 Ini 注释
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="comment">注释</param>
|
||||||
|
public IniComment(string comment)
|
||||||
|
{
|
||||||
|
Comment = comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 注释
|
||||||
|
/// </summary>
|
||||||
|
public string Comment { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $";{Comment}";
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniElement.cs
Normal file
16
src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniElement.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Core.IO.Ini;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ini 元素
|
||||||
|
/// </summary>
|
||||||
|
internal abstract class IniElement
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 将当前元素转换到等价的字符串表示
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>字符串</returns>
|
||||||
|
public new abstract string ToString();
|
||||||
|
}
|
||||||
37
src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniParameter.cs
Normal file
37
src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniParameter.cs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Core.IO.Ini;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ini 参数
|
||||||
|
/// </summary>
|
||||||
|
internal class IniParameter : IniElement
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Ini 参数
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">键</param>
|
||||||
|
/// <param name="value">值</param>
|
||||||
|
public IniParameter(string key, string value)
|
||||||
|
{
|
||||||
|
Key = key;
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 键
|
||||||
|
/// </summary>
|
||||||
|
public string Key { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 值
|
||||||
|
/// </summary>
|
||||||
|
public string Value { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"{Key}={Value}";
|
||||||
|
}
|
||||||
|
}
|
||||||
31
src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniSection.cs
Normal file
31
src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniSection.cs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Core.IO.Ini;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ini 节
|
||||||
|
/// </summary>
|
||||||
|
internal class IniSection : IniElement
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 构造一个新的Ini 节
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">名称</param>
|
||||||
|
/// <param name="elements">元素</param>
|
||||||
|
public IniSection(string name)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 名称
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"[{Name}]";
|
||||||
|
}
|
||||||
|
}
|
||||||
47
src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniSerializer.cs
Normal file
47
src/Snap.Hutao/Snap.Hutao/Core/IO/Ini/IniSerializer.cs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Core.IO.Ini;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ini 序列化器
|
||||||
|
/// </summary>
|
||||||
|
internal static class IniSerializer
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 异步反序列化
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fileStream">文件流</param>
|
||||||
|
/// <returns>Ini 元素集合</returns>
|
||||||
|
public static IEnumerable<IniElement> Deserialize(FileStream fileStream)
|
||||||
|
{
|
||||||
|
using (TextReader reader = new StreamReader(fileStream))
|
||||||
|
{
|
||||||
|
while (reader.ReadLine() is string line)
|
||||||
|
{
|
||||||
|
if (line.Length > 0)
|
||||||
|
{
|
||||||
|
if (line[0] == '[')
|
||||||
|
{
|
||||||
|
yield return new IniSection(line[1..^1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line[0] == ';')
|
||||||
|
{
|
||||||
|
yield return new IniComment(line[1..]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.IndexOf('=') > 0)
|
||||||
|
{
|
||||||
|
string[] parameters = line.Split('=', 2);
|
||||||
|
yield return new IniParameter(parameters[0], parameters[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using Microsoft.Windows.AppLifecycle;
|
using Microsoft.Windows.AppLifecycle;
|
||||||
using Snap.Hutao.Core.Threading;
|
using Snap.Hutao.Core.Threading;
|
||||||
using Snap.Hutao.Extension;
|
|
||||||
using Snap.Hutao.Service.Abstraction;
|
using Snap.Hutao.Service.Abstraction;
|
||||||
using Snap.Hutao.Service.Navigation;
|
using Snap.Hutao.Service.Navigation;
|
||||||
|
|
||||||
|
|||||||
@@ -70,9 +70,8 @@ public sealed class LogEntryQueue : IDisposable
|
|||||||
logDbContext.Database.Migrate();
|
logDbContext.Database.Migrate();
|
||||||
}
|
}
|
||||||
|
|
||||||
logDbContext.Logs.RemoveRange(logDbContext.Logs);
|
// only raw sql can pass
|
||||||
logDbContext.SaveChanges();
|
logDbContext.Database.ExecuteSqlRaw("DELETE FROM logs WHERE Exception IS NULL");
|
||||||
|
|
||||||
return logDbContext;
|
return logDbContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
namespace Snap.Hutao.Extension;
|
namespace Snap.Hutao.Core.Threading;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 信号量扩展
|
/// 信号量扩展
|
||||||
@@ -15,7 +15,7 @@ public static class SemaphoreSlimExtensions
|
|||||||
/// <returns>可释放的对象,用于释放信号量</returns>
|
/// <returns>可释放的对象,用于释放信号量</returns>
|
||||||
public static async Task<IDisposable> EnterAsync(this SemaphoreSlim semaphoreSlim)
|
public static async Task<IDisposable> EnterAsync(this SemaphoreSlim semaphoreSlim)
|
||||||
{
|
{
|
||||||
await semaphoreSlim.WaitAsync();
|
await semaphoreSlim.WaitAsync().ConfigureAwait(false);
|
||||||
return new SemaphoreSlimReleaser(semaphoreSlim);
|
return new SemaphoreSlimReleaser(semaphoreSlim);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8,7 +8,7 @@ namespace Snap.Hutao.Extension;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// <see cref="BinaryReader"/> 扩展
|
/// <see cref="BinaryReader"/> 扩展
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class BinaryReaderExtensions
|
public static class BinaryReaderExtension
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 判断是否处于流的结尾
|
/// 判断是否处于流的结尾
|
||||||
@@ -6,7 +6,7 @@ namespace Snap.Hutao.Extension;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// <see cref="DateTimeOffset"/> 扩展
|
/// <see cref="DateTimeOffset"/> 扩展
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class DateTimeOffsetExtensions
|
public static class DateTimeOffsetExtension
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Converts the current <see cref="DateTimeOffset"/> to a <see cref="DateTimeOffset"/> that represents the local time.
|
/// Converts the current <see cref="DateTimeOffset"/> to a <see cref="DateTimeOffset"/> that represents the local time.
|
||||||
@@ -8,7 +8,7 @@ namespace Snap.Hutao.Extension;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 枚举拓展
|
/// 枚举拓展
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class EnumExtensions
|
public static class EnumExtension
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取枚举的描述
|
/// 获取枚举的描述
|
||||||
@@ -9,7 +9,7 @@ namespace Snap.Hutao.Extension;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// <see cref="IEnumerable{T}"/> 扩展
|
/// <see cref="IEnumerable{T}"/> 扩展
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static partial class EnumerableExtensions
|
public static partial class EnumerableExtension
|
||||||
{
|
{
|
||||||
/// <inheritdoc cref="Enumerable.Average(IEnumerable{int})"/>
|
/// <inheritdoc cref="Enumerable.Average(IEnumerable{int})"/>
|
||||||
public static double AverageNoThrow(this List<int> source)
|
public static double AverageNoThrow(this List<int> source)
|
||||||
@@ -6,7 +6,7 @@ namespace Snap.Hutao.Extension;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 数高性能扩展
|
/// 数高性能扩展
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class NumberExtensions
|
public static class NumberExtension
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取从右向左某位上的数字
|
/// 获取从右向左某位上的数字
|
||||||
@@ -6,7 +6,7 @@ namespace Snap.Hutao.Extension;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 对象扩展
|
/// 对象扩展
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class ObjectExtensions
|
public static class ObjectExtension
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <see langword="as"/> 的链式调用扩展
|
/// <see langword="as"/> 的链式调用扩展
|
||||||
@@ -8,7 +8,7 @@ namespace Snap.Hutao.Extension;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 包版本扩展
|
/// 包版本扩展
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class PackageVersionExtensions
|
public static class PackageVersionExtension
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 将包版本转换为版本
|
/// 将包版本转换为版本
|
||||||
@@ -11,8 +11,19 @@ public class Reliquary : EquipBase
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 副属性列表
|
/// 副属性列表
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Obsolete]
|
||||||
public List<ReliquarySubProperty> SubProperties { get; set; } = default!;
|
public List<ReliquarySubProperty> SubProperties { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 初始词条
|
||||||
|
/// </summary>
|
||||||
|
public List<ReliquarySubProperty> PrimarySubProperties { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 强化词条
|
||||||
|
/// </summary>
|
||||||
|
public List<ReliquarySubProperty> SecondarySubProperties { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 评分
|
/// 评分
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ public class UIAFInfo
|
|||||||
public DateTimeOffset ExportDateTime
|
public DateTimeOffset ExportDateTime
|
||||||
{
|
{
|
||||||
// Hot fix | 1.0.31 | UIAF.Info.ExportTimestamp can be milliseconds
|
// Hot fix | 1.0.31 | UIAF.Info.ExportTimestamp can be milliseconds
|
||||||
get => DateTimeOffsetExtensions.FromUnixTime(ExportTimestamp, DateTimeOffset.MinValue);
|
get => DateTimeOffsetExtension.FromUnixTime(ExportTimestamp, DateTimeOffset.MinValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -32,9 +32,10 @@ public class UIGFInfo
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 导出时间
|
/// 导出时间
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[JsonIgnore]
|
||||||
public DateTimeOffset ExportDateTime
|
public DateTimeOffset ExportDateTime
|
||||||
{
|
{
|
||||||
get => DateTimeOffsetExtensions.FromUnixTime(ExportTimestamp, DateTimeOffset.MinValue);
|
get => DateTimeOffsetExtension.FromUnixTime(ExportTimestamp, DateTimeOffset.MinValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -11,10 +11,13 @@ public static class AvatarIds
|
|||||||
{
|
{
|
||||||
public const int Ayaka = 10000002;
|
public const int Ayaka = 10000002;
|
||||||
public const int Qin = 10000003;
|
public const int Qin = 10000003;
|
||||||
|
|
||||||
public const int Lisa = 10000006;
|
public const int Lisa = 10000006;
|
||||||
|
|
||||||
public const int Barbara = 10000014;
|
public const int Barbara = 10000014;
|
||||||
public const int Kaeya = 10000015;
|
public const int Kaeya = 10000015;
|
||||||
public const int Diluc = 10000016;
|
public const int Diluc = 10000016;
|
||||||
|
|
||||||
public const int Razor = 10000020;
|
public const int Razor = 10000020;
|
||||||
public const int Ambor = 10000021;
|
public const int Ambor = 10000021;
|
||||||
public const int Venti = 10000022;
|
public const int Venti = 10000022;
|
||||||
@@ -23,6 +26,7 @@ public static class AvatarIds
|
|||||||
public const int Xingqiu = 10000025;
|
public const int Xingqiu = 10000025;
|
||||||
public const int Xiao = 10000026;
|
public const int Xiao = 10000026;
|
||||||
public const int Ningguang = 10000027;
|
public const int Ningguang = 10000027;
|
||||||
|
|
||||||
public const int Klee = 10000029;
|
public const int Klee = 10000029;
|
||||||
public const int Zhongli = 10000030;
|
public const int Zhongli = 10000030;
|
||||||
public const int Fischl = 10000031;
|
public const int Fischl = 10000031;
|
||||||
@@ -34,6 +38,7 @@ public static class AvatarIds
|
|||||||
public const int Ganyu = 10000037;
|
public const int Ganyu = 10000037;
|
||||||
public const int Albedo = 10000038;
|
public const int Albedo = 10000038;
|
||||||
public const int Diona = 10000039;
|
public const int Diona = 10000039;
|
||||||
|
|
||||||
public const int Mona = 10000041;
|
public const int Mona = 10000041;
|
||||||
public const int Keqing = 10000042;
|
public const int Keqing = 10000042;
|
||||||
public const int Sucrose = 10000043;
|
public const int Sucrose = 10000043;
|
||||||
@@ -54,6 +59,7 @@ public static class AvatarIds
|
|||||||
public const int Yae = 10000058;
|
public const int Yae = 10000058;
|
||||||
public const int Heizou = 10000059;
|
public const int Heizou = 10000059;
|
||||||
public const int Yelan = 10000060;
|
public const int Yelan = 10000060;
|
||||||
|
|
||||||
public const int Aloy = 10000062;
|
public const int Aloy = 10000062;
|
||||||
public const int Shenhe = 10000063;
|
public const int Shenhe = 10000063;
|
||||||
public const int Yunjin = 10000064;
|
public const int Yunjin = 10000064;
|
||||||
@@ -62,6 +68,7 @@ public static class AvatarIds
|
|||||||
public const int Collei = 10000067;
|
public const int Collei = 10000067;
|
||||||
public const int Dori = 10000068;
|
public const int Dori = 10000068;
|
||||||
public const int Tighnari = 10000069;
|
public const int Tighnari = 10000069;
|
||||||
|
public const int Nilou = 10000070;
|
||||||
public const int Cyno = 10000071;
|
public const int Cyno = 10000071;
|
||||||
public const int Candace = 10000072;
|
public const int Candace = 10000072;
|
||||||
}
|
}
|
||||||
@@ -61,7 +61,10 @@ public class Weapon : IStatisticsItemSource, ISummaryItemSource, INameQuality
|
|||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public ItemQuality Quality => RankLevel;
|
public ItemQuality Quality
|
||||||
|
{
|
||||||
|
get => RankLevel;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 转换为基础物品
|
/// 转换为基础物品
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<Identity
|
<Identity
|
||||||
Name="7f0db578-026f-4e0b-a75b-d5d06bb0a74d"
|
Name="7f0db578-026f-4e0b-a75b-d5d06bb0a74d"
|
||||||
Publisher="CN=DGP Studio"
|
Publisher="CN=DGP Studio"
|
||||||
Version="1.1.9.0" />
|
Version="1.1.11.0" />
|
||||||
|
|
||||||
<Properties>
|
<Properties>
|
||||||
<DisplayName>胡桃</DisplayName>
|
<DisplayName>胡桃</DisplayName>
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Service.Abstraction;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 胡桃 API 服务
|
||||||
|
/// </summary>
|
||||||
|
internal interface IHutaoService
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -117,6 +117,11 @@ internal class AvatarInfoService : IAvatarInfoService
|
|||||||
|
|
||||||
foreach (Web.Enka.Model.AvatarInfo webInfo in webInfos)
|
foreach (Web.Enka.Model.AvatarInfo webInfo in webInfos)
|
||||||
{
|
{
|
||||||
|
if (webInfo.AvatarId == 10000005 || webInfo.AvatarId == 10000007)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
Model.Entity.AvatarInfo? entity = dbInfos.SingleOrDefault(i => i.Info.AvatarId == webInfo.AvatarId);
|
Model.Entity.AvatarInfo? entity = dbInfos.SingleOrDefault(i => i.Info.AvatarId == webInfo.AvatarId);
|
||||||
|
|
||||||
if (entity == null)
|
if (entity == null)
|
||||||
@@ -141,8 +146,9 @@ internal class AvatarInfoService : IAvatarInfoService
|
|||||||
return appDbContext.AvatarInfos
|
return appDbContext.AvatarInfos
|
||||||
.Where(i => i.Uid == uid)
|
.Where(i => i.Uid == uid)
|
||||||
.Select(i => i.Info)
|
.Select(i => i.Info)
|
||||||
.AsEnumerable()
|
|
||||||
.OrderByDescending(i => i.AvatarId)
|
// .AsEnumerable()
|
||||||
|
// .OrderByDescending(i => i.AvatarId)
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -11,8 +11,14 @@ namespace Snap.Hutao.Service.AvatarInfo.Factory;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal static partial class ReliquaryWeightConfiguration
|
internal static partial class ReliquaryWeightConfiguration
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 默认
|
||||||
|
/// </summary>
|
||||||
|
public static readonly AffixWeight Default = new(0, 100, 75, 0, 100, 100, 0, 55, 0) { { FightProperty.FIGHT_PROP_WATER_ADD_HURT, 100 } };
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 词条权重
|
/// 词条权重
|
||||||
|
/// https://docs.qq.com/sheet/DUG52SFJlTUN3cmNL?tab=BB08J2
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly List<AffixWeight> AffixWeights = new()
|
public static readonly List<AffixWeight> AffixWeights = new()
|
||||||
{
|
{
|
||||||
@@ -73,6 +79,8 @@ internal static partial class ReliquaryWeightConfiguration
|
|||||||
new(AvatarIds.Collei, 0, 75, 0, 100, 100, 0, 55, 0) { { FightProperty.FIGHT_PROP_GRASS_ADD_HURT, 100 } },
|
new(AvatarIds.Collei, 0, 75, 0, 100, 100, 0, 55, 0) { { FightProperty.FIGHT_PROP_GRASS_ADD_HURT, 100 } },
|
||||||
new(AvatarIds.Dori, 100, 75, 0, 100, 100, 0, 55, 0) { { FightProperty.FIGHT_PROP_ELEC_ADD_HURT, 100 } },
|
new(AvatarIds.Dori, 100, 75, 0, 100, 100, 0, 55, 0) { { FightProperty.FIGHT_PROP_ELEC_ADD_HURT, 100 } },
|
||||||
new(AvatarIds.Tighnari, 0, 75, 0, 100, 100, 0, 55, 0) { { FightProperty.FIGHT_PROP_GRASS_ADD_HURT, 100 } },
|
new(AvatarIds.Tighnari, 0, 75, 0, 100, 100, 0, 55, 0) { { FightProperty.FIGHT_PROP_GRASS_ADD_HURT, 100 } },
|
||||||
|
new(AvatarIds.Nilou, 100, 75, 0, 100, 100, 0, 55, 0, "直伤流") { { FightProperty.FIGHT_PROP_WATER_ADD_HURT, 100 } },
|
||||||
|
new(AvatarIds.Nilou, 100, 75, 0, 100, 100, 0, 55, 0, "反应流") { { FightProperty.FIGHT_PROP_WATER_ADD_HURT, 100 } },
|
||||||
new(AvatarIds.Cyno, 0, 75, 0, 100, 100, 75, 55, 0) { { FightProperty.FIGHT_PROP_ELEC_ADD_HURT, 100 } },
|
new(AvatarIds.Cyno, 0, 75, 0, 100, 100, 75, 55, 0) { { FightProperty.FIGHT_PROP_ELEC_ADD_HURT, 100 } },
|
||||||
new(AvatarIds.Candace, 100, 75, 0, 100, 100, 0, 55, 0) { { FightProperty.FIGHT_PROP_WATER_ADD_HURT, 100 } },
|
new(AvatarIds.Candace, 100, 75, 0, 100, 100, 0, 55, 0) { { FightProperty.FIGHT_PROP_WATER_ADD_HURT, 100 } },
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
using Snap.Hutao.Extension;
|
using Snap.Hutao.Extension;
|
||||||
using Snap.Hutao.Model;
|
using Snap.Hutao.Model;
|
||||||
using Snap.Hutao.Model.Binding.AvatarProperty;
|
|
||||||
using Snap.Hutao.Model.Intrinsic;
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
using Snap.Hutao.Model.Metadata.Converter;
|
using Snap.Hutao.Model.Metadata.Converter;
|
||||||
using Snap.Hutao.Model.Metadata.Reliquary;
|
using Snap.Hutao.Model.Metadata.Reliquary;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using Snap.Hutao.Model.Intrinsic;
|
|||||||
using Snap.Hutao.Model.Metadata.Converter;
|
using Snap.Hutao.Model.Metadata.Converter;
|
||||||
using Snap.Hutao.Model.Metadata.Reliquary;
|
using Snap.Hutao.Model.Metadata.Reliquary;
|
||||||
using Snap.Hutao.Web.Enka.Model;
|
using Snap.Hutao.Web.Enka.Model;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using MetadataReliquary = Snap.Hutao.Model.Metadata.Reliquary.Reliquary;
|
using MetadataReliquary = Snap.Hutao.Model.Metadata.Reliquary.Reliquary;
|
||||||
using MetadataReliquaryAffix = Snap.Hutao.Model.Metadata.Reliquary.ReliquaryAffix;
|
using MetadataReliquaryAffix = Snap.Hutao.Model.Metadata.Reliquary.ReliquaryAffix;
|
||||||
using ModelAvatarInfo = Snap.Hutao.Web.Enka.Model.AvatarInfo;
|
using ModelAvatarInfo = Snap.Hutao.Web.Enka.Model.AvatarInfo;
|
||||||
@@ -61,6 +62,12 @@ internal class SummaryReliquaryFactory
|
|||||||
{
|
{
|
||||||
MetadataReliquary reliquary = reliquaries.Single(r => r.Ids.Contains(equip.ItemId));
|
MetadataReliquary reliquary = reliquaries.Single(r => r.Ids.Contains(equip.ItemId));
|
||||||
List<ReliquarySubProperty> subProperty = equip.Reliquary!.AppendPropIdList.Select(id => CreateSubProperty(id)).ToList();
|
List<ReliquarySubProperty> subProperty = equip.Reliquary!.AppendPropIdList.Select(id => CreateSubProperty(id)).ToList();
|
||||||
|
|
||||||
|
int affixCount = GetAffixCount(reliquary);
|
||||||
|
Span<ReliquarySubProperty> span = CollectionsMarshal.AsSpan(subProperty);
|
||||||
|
List<ReliquarySubProperty> primary = new(span[..^affixCount].ToArray());
|
||||||
|
List<ReliquarySubProperty> secondary = new(span[^affixCount..].ToArray());
|
||||||
|
|
||||||
ReliquaryLevel relicLevel = reliqueryLevels.Single(r => r.Level == equip.Reliquary!.Level && r.Quality == reliquary.RankLevel);
|
ReliquaryLevel relicLevel = reliqueryLevels.Single(r => r.Level == equip.Reliquary!.Level && r.Quality == reliquary.RankLevel);
|
||||||
FightProperty property = idRelicMainPropMap[equip.Reliquary.MainPropId];
|
FightProperty property = idRelicMainPropMap[equip.Reliquary.MainPropId];
|
||||||
|
|
||||||
@@ -77,21 +84,55 @@ internal class SummaryReliquaryFactory
|
|||||||
MainProperty = new(property.GetDescription(), PropertyInfoDescriptor.FormatValue(property, relicLevel.Properties[property])),
|
MainProperty = new(property.GetDescription(), PropertyInfoDescriptor.FormatValue(property, relicLevel.Properties[property])),
|
||||||
|
|
||||||
// Reliquary
|
// Reliquary
|
||||||
SubProperties = subProperty,
|
// SubProperties = subProperty,
|
||||||
|
PrimarySubProperties = primary,
|
||||||
|
SecondarySubProperties = secondary,
|
||||||
Score = ScoreReliquary(property, reliquary, relicLevel, subProperty),
|
Score = ScoreReliquary(property, reliquary, relicLevel, subProperty),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int GetAffixCount(MetadataReliquary reliquary)
|
||||||
|
{
|
||||||
|
return (reliquary.RankLevel, equip.Reliquary!.Level) switch
|
||||||
|
{
|
||||||
|
(ItemQuality.QUALITY_ORANGE, > 20) => 5,
|
||||||
|
(ItemQuality.QUALITY_ORANGE, > 16) => 4,
|
||||||
|
(ItemQuality.QUALITY_ORANGE, > 12) => 3,
|
||||||
|
(ItemQuality.QUALITY_ORANGE, > 8) => 2,
|
||||||
|
(ItemQuality.QUALITY_ORANGE, > 4) => 1,
|
||||||
|
(ItemQuality.QUALITY_ORANGE, _) => 0,
|
||||||
|
|
||||||
|
(ItemQuality.QUALITY_PURPLE, > 16) => 4,
|
||||||
|
(ItemQuality.QUALITY_PURPLE, > 12) => 3,
|
||||||
|
(ItemQuality.QUALITY_PURPLE, > 8) => 2,
|
||||||
|
(ItemQuality.QUALITY_PURPLE, > 4) => 1,
|
||||||
|
(ItemQuality.QUALITY_PURPLE, _) => 0,
|
||||||
|
|
||||||
|
(ItemQuality.QUALITY_BLUE, > 12) => 3,
|
||||||
|
(ItemQuality.QUALITY_BLUE, > 8) => 2,
|
||||||
|
(ItemQuality.QUALITY_BLUE, > 4) => 1,
|
||||||
|
(ItemQuality.QUALITY_BLUE, _) => 0,
|
||||||
|
|
||||||
|
(ItemQuality.QUALITY_GREEN, > 4) => 1,
|
||||||
|
(ItemQuality.QUALITY_GREEN, _) => 0,
|
||||||
|
|
||||||
|
(ItemQuality.QUALITY_WHITE, > 4) => 1,
|
||||||
|
(ItemQuality.QUALITY_WHITE, _) => 0,
|
||||||
|
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private double ScoreReliquary(FightProperty property, MetadataReliquary reliquary, ReliquaryLevel relicLevel, List<ReliquarySubProperty> subProperties)
|
private double ScoreReliquary(FightProperty property, MetadataReliquary reliquary, ReliquaryLevel relicLevel, List<ReliquarySubProperty> subProperties)
|
||||||
{
|
{
|
||||||
// 沙 杯 头
|
// 沙 杯 头
|
||||||
if (equip.Flat.EquipType is EquipType.EQUIP_SHOES or EquipType.EQUIP_RING or EquipType.EQUIP_DRESS)
|
if (equip.Flat.EquipType is EquipType.EQUIP_SHOES or EquipType.EQUIP_RING or EquipType.EQUIP_DRESS)
|
||||||
{
|
{
|
||||||
AffixWeight weightConfig = GetAffixWeightForAvatarId(avatarInfo.AvatarId);
|
AffixWeight weightConfig = GetAffixWeightForAvatarId();
|
||||||
ReliquaryLevel maxRelicLevel = reliqueryLevels.Where(r => r.Quality == reliquary.RankLevel).MaxBy(r => r.Level)!;
|
ReliquaryLevel maxRelicLevel = reliqueryLevels.Where(r => r.Quality == reliquary.RankLevel).MaxBy(r => r.Level)!;
|
||||||
|
|
||||||
double percent = relicLevel.Properties[property] / maxRelicLevel.Properties[property];
|
double percent = relicLevel.Properties[property] / maxRelicLevel.Properties[property];
|
||||||
double baseScore = 8 * percent * weightConfig[property];
|
double baseScore = 8 * percent * weightConfig.GetValueOrDefault(property, 0);
|
||||||
|
|
||||||
double score = subProperties.Sum(p => p.Score);
|
double score = subProperties.Sum(p => p.Score);
|
||||||
return ((score + baseScore) / 1700) * 66;
|
return ((score + baseScore) / 1700) * 66;
|
||||||
@@ -103,9 +144,9 @@ internal class SummaryReliquaryFactory
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private AffixWeight GetAffixWeightForAvatarId(int avatarId)
|
private AffixWeight GetAffixWeightForAvatarId()
|
||||||
{
|
{
|
||||||
return ReliquaryWeightConfiguration.AffixWeights.First(w => w.AvatarId == avatarId);
|
return ReliquaryWeightConfiguration.AffixWeights.FirstOrDefault(w => w.AvatarId == avatarInfo.AvatarId, ReliquaryWeightConfiguration.Default);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ReliquarySubProperty CreateSubProperty(int appendPropId)
|
private ReliquarySubProperty CreateSubProperty(int appendPropId)
|
||||||
@@ -121,7 +162,7 @@ internal class SummaryReliquaryFactory
|
|||||||
{
|
{
|
||||||
MetadataReliquaryAffix affix = idReliquaryAffixMap[appendId];
|
MetadataReliquaryAffix affix = idReliquaryAffixMap[appendId];
|
||||||
|
|
||||||
AffixWeight weightConfig = GetAffixWeightForAvatarId(avatarInfo.AvatarId);
|
AffixWeight weightConfig = GetAffixWeightForAvatarId();
|
||||||
double weight = weightConfig.GetValueOrDefault(affix.Type, 0) / 100D;
|
double weight = weightConfig.GetValueOrDefault(affix.Type, 0) / 100D;
|
||||||
|
|
||||||
// 小字词条,转换到等效百分比计算
|
// 小字词条,转换到等效百分比计算
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ internal class GachaLogService : IGachaLogService, ISupportAsyncInitialization
|
|||||||
{
|
{
|
||||||
Verify.Operation(IsInitialized, "祈愿记录服务未能正常初始化");
|
Verify.Operation(IsInitialized, "祈愿记录服务未能正常初始化");
|
||||||
|
|
||||||
var list = appDbContext.GachaItems
|
List<UIGFItem> list = appDbContext.GachaItems
|
||||||
.Where(i => i.ArchiveId == archive.InnerId)
|
.Where(i => i.ArchiveId == archive.InnerId)
|
||||||
.AsEnumerable()
|
.AsEnumerable()
|
||||||
.Select(i => i.ToUIGFItem(GetNameQualityByItemId(i.ItemId)))
|
.Select(i => i.ToUIGFItem(GetNameQualityByItemId(i.ItemId)))
|
||||||
|
|||||||
@@ -2,7 +2,10 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
|
using Snap.Hutao.Core.IO.Ini;
|
||||||
using Snap.Hutao.Core.Threading;
|
using Snap.Hutao.Core.Threading;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace Snap.Hutao.Service.Game.Locator;
|
namespace Snap.Hutao.Service.Game.Locator;
|
||||||
|
|
||||||
@@ -18,8 +21,30 @@ internal class RegistryLauncherLocator : IGameLocator
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public Task<ValueResult<bool, string>> LocateGamePathAsync()
|
public Task<ValueResult<bool, string>> LocateGamePathAsync()
|
||||||
{
|
{
|
||||||
// TODO: fix folder moved issue
|
ValueResult<bool, string> result = LocateInternal("InstallPath");
|
||||||
return Task.FromResult(LocateInternal("InstallPath", "\\Genshin Impact Game\\YuanShen.exe"));
|
|
||||||
|
if (result.IsOk == false)
|
||||||
|
{
|
||||||
|
return Task.FromResult(result);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string path = result.Value;
|
||||||
|
string configPath = Path.Combine(path, "config.ini");
|
||||||
|
string? escapedPath = null;
|
||||||
|
using (FileStream stream = File.OpenRead(configPath))
|
||||||
|
{
|
||||||
|
IEnumerable<IniElement> elements = IniSerializer.Deserialize(stream);
|
||||||
|
escapedPath = elements.OfType<IniParameter>().FirstOrDefault(p => p.Key == "game_install_path")?.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (escapedPath != null)
|
||||||
|
{
|
||||||
|
return Task.FromResult<ValueResult<bool, string>>(new(true, Unescape(escapedPath)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.FromResult<ValueResult<bool, string>>(new(false, null!));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
@@ -28,18 +53,13 @@ internal class RegistryLauncherLocator : IGameLocator
|
|||||||
return Task.FromResult(LocateInternal("DisplayIcon"));
|
return Task.FromResult(LocateInternal("DisplayIcon"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ValueResult<bool, string> LocateInternal(string key, string? append = null)
|
private static ValueResult<bool, string> LocateInternal(string key)
|
||||||
{
|
{
|
||||||
RegistryKey? uninstallKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\原神");
|
RegistryKey? uninstallKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\原神");
|
||||||
if (uninstallKey != null)
|
if (uninstallKey != null)
|
||||||
{
|
{
|
||||||
if (uninstallKey.GetValue(key) is string path)
|
if (uninstallKey.GetValue(key) is string path)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(append))
|
|
||||||
{
|
|
||||||
path += append;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new(true, path);
|
return new(true, path);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -52,4 +72,18 @@ internal class RegistryLauncherLocator : IGameLocator
|
|||||||
return new(false, null!);
|
return new(false, null!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string Unescape(string str)
|
||||||
|
{
|
||||||
|
string? hex4Result = Regex.Replace(str, @"\\x([0-9a-f]{4})", @"\u$1");
|
||||||
|
|
||||||
|
// 不包含中文
|
||||||
|
if (!hex4Result.Contains(@"\u"))
|
||||||
|
{
|
||||||
|
// fix path with \
|
||||||
|
hex4Result = hex4Result.Replace(@"\", @"\\");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Regex.Unescape(hex4Result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
27
src/Snap.Hutao/Snap.Hutao/Service/HutaoService.cs
Normal file
27
src/Snap.Hutao/Snap.Hutao/Service/HutaoService.cs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
using Snap.Hutao.Service.Abstraction;
|
||||||
|
using Snap.Hutao.Web.Hutao;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Service;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 胡桃 API 服务
|
||||||
|
/// </summary>
|
||||||
|
[Injection(InjectAs.Transient)]
|
||||||
|
internal class HutaoService : IHutaoService
|
||||||
|
{
|
||||||
|
private readonly HomaClient homaClient;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构造一个新的胡桃 API 服务
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="homaClient">胡桃 API 客户端</param>
|
||||||
|
/// <param name="memoryCache">内存缓存</param>
|
||||||
|
public HutaoService(HomaClient homaClient, IMemoryCache memoryCache)
|
||||||
|
{
|
||||||
|
this.homaClient = homaClient;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,6 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using CommunityToolkit.Mvvm.Messaging;
|
|
||||||
using Snap.Hutao.Context.Database;
|
|
||||||
using Snap.Hutao.Core.Threading;
|
|
||||||
using Snap.Hutao.Web.Hoyolab;
|
|
||||||
using Snap.Hutao.Web.Hoyolab.Bbs.User;
|
|
||||||
using Snap.Hutao.Web.Hoyolab.Takumi.Auth;
|
|
||||||
using Snap.Hutao.Web.Hoyolab.Takumi.Binding;
|
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using BindingUser = Snap.Hutao.Model.Binding.User;
|
using BindingUser = Snap.Hutao.Model.Binding.User;
|
||||||
|
|
||||||
|
|||||||
@@ -154,12 +154,18 @@ internal class UserService : IUserService
|
|||||||
{
|
{
|
||||||
// insert stoken directly
|
// insert stoken directly
|
||||||
userWithSameUid.Cookie.InsertSToken(uid, cookie);
|
userWithSameUid.Cookie.InsertSToken(uid, cookie);
|
||||||
|
appDbContext.Users.Update(userWithSameUid.Entity);
|
||||||
|
appDbContext.SaveChanges();
|
||||||
|
|
||||||
return new(UserOptionResult.Upgraded, uid);
|
return new(UserOptionResult.Upgraded, uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cookie.ContainsLTokenAndCookieToken())
|
if (cookie.ContainsLTokenAndCookieToken())
|
||||||
{
|
{
|
||||||
UpdateUserCookie(cookie, userWithSameUid);
|
userWithSameUid.Cookie = cookie;
|
||||||
|
appDbContext.Users.Update(userWithSameUid.Entity);
|
||||||
|
appDbContext.SaveChanges();
|
||||||
|
|
||||||
return new(UserOptionResult.Updated, uid);
|
return new(UserOptionResult.Updated, uid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -189,14 +195,6 @@ internal class UserService : IUserService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateUserCookie(Cookie cookie, BindingUser user)
|
|
||||||
{
|
|
||||||
user.Cookie = cookie;
|
|
||||||
|
|
||||||
appDbContext.Users.Update(user.Entity);
|
|
||||||
appDbContext.SaveChanges();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<ValueResult<UserOptionResult, string>> TryCreateUserAndAddAsync(ObservableCollection<BindingUser> users, Cookie cookie)
|
private async Task<ValueResult<UserOptionResult, string>> TryCreateUserAndAddAsync(ObservableCollection<BindingUser> users, Cookie cookie)
|
||||||
{
|
{
|
||||||
cookie.Trim();
|
cookie.Trim();
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ using Microsoft.UI.Xaml;
|
|||||||
using Microsoft.UI.Xaml.Controls;
|
using Microsoft.UI.Xaml.Controls;
|
||||||
using Snap.Hutao.Core;
|
using Snap.Hutao.Core;
|
||||||
using Snap.Hutao.Model.Metadata;
|
using Snap.Hutao.Model.Metadata;
|
||||||
using System.Diagnostics;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.View.Control;
|
namespace Snap.Hutao.View.Control;
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ public sealed partial class UserAutoCookieDialog : ContentDialog
|
|||||||
|
|
||||||
CoreWebView2CookieManager manager = WebView.CoreWebView2.CookieManager;
|
CoreWebView2CookieManager manager = WebView.CoreWebView2.CookieManager;
|
||||||
IReadOnlyList<CoreWebView2Cookie> cookies = await manager.GetCookiesAsync("https://user.mihoyo.com");
|
IReadOnlyList<CoreWebView2Cookie> cookies = await manager.GetCookiesAsync("https://user.mihoyo.com");
|
||||||
foreach (var item in cookies)
|
foreach (CoreWebView2Cookie item in cookies)
|
||||||
{
|
{
|
||||||
manager.DeleteCookie(item);
|
manager.DeleteCookie(item);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ using Snap.Hutao.Core.Threading;
|
|||||||
using Snap.Hutao.Service.Abstraction;
|
using Snap.Hutao.Service.Abstraction;
|
||||||
using Snap.Hutao.Service.Navigation;
|
using Snap.Hutao.Service.Navigation;
|
||||||
using Snap.Hutao.View.Page;
|
using Snap.Hutao.View.Page;
|
||||||
using Windows.UI.ViewManagement;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.View;
|
namespace Snap.Hutao.View;
|
||||||
|
|
||||||
|
|||||||
@@ -520,34 +520,65 @@
|
|||||||
Width="80"
|
Width="80"
|
||||||
Height="80"
|
Height="80"
|
||||||
Source="{Binding Icon}"/>
|
Source="{Binding Icon}"/>
|
||||||
<ItemsControl
|
<Grid Grid.Row="2">
|
||||||
VerticalAlignment="Stretch"
|
<Grid.ColumnDefinitions>
|
||||||
Grid.Row="2"
|
<ColumnDefinition/>
|
||||||
ItemsSource="{Binding SubProperties}">
|
<ColumnDefinition Width="16"/>
|
||||||
<ItemsControl.ItemsPanel>
|
<ColumnDefinition/>
|
||||||
<ItemsPanelTemplate>
|
</Grid.ColumnDefinitions>
|
||||||
<cwucont:UniformGrid
|
<ItemsControl
|
||||||
Columns="2"
|
MinWidth="156"
|
||||||
Rows="5"
|
Grid.Column="0"
|
||||||
ColumnSpacing="16"
|
VerticalAlignment="Stretch"
|
||||||
Orientation="Vertical"/>
|
ItemsSource="{Binding PrimarySubProperties}">
|
||||||
</ItemsPanelTemplate>
|
<ItemsControl.ItemsPanel>
|
||||||
</ItemsControl.ItemsPanel>
|
<ItemsPanelTemplate>
|
||||||
<ItemsControl.ItemTemplate>
|
<cwucont:UniformGrid
|
||||||
<DataTemplate>
|
Columns="1"
|
||||||
<Grid Padding="2" MinWidth="152" Opacity="{Binding Opacity}">
|
Rows="5"
|
||||||
<Grid.RowDefinitions>
|
Orientation="Vertical"/>
|
||||||
<RowDefinition/>
|
</ItemsPanelTemplate>
|
||||||
</Grid.RowDefinitions>
|
</ItemsControl.ItemsPanel>
|
||||||
<TextBlock
|
<ItemsControl.ItemTemplate>
|
||||||
Text="{Binding Name}"/>
|
<DataTemplate>
|
||||||
<TextBlock
|
<Grid Padding="2" Opacity="{Binding Opacity}">
|
||||||
Text="{Binding Value}"
|
<TextBlock
|
||||||
HorizontalAlignment="Right"/>
|
Text="{Binding Name}"/>
|
||||||
</Grid>
|
<TextBlock
|
||||||
</DataTemplate>
|
Text="{Binding Value}"
|
||||||
</ItemsControl.ItemTemplate>
|
HorizontalAlignment="Right"/>
|
||||||
</ItemsControl>
|
</Grid>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
|
|
||||||
|
<ItemsControl
|
||||||
|
MinWidth="156"
|
||||||
|
Grid.Column="2"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
ItemsSource="{Binding SecondarySubProperties}">
|
||||||
|
<ItemsControl.ItemsPanel>
|
||||||
|
<ItemsPanelTemplate>
|
||||||
|
<cwucont:UniformGrid
|
||||||
|
Columns="1"
|
||||||
|
Rows="5"
|
||||||
|
Orientation="Vertical"/>
|
||||||
|
</ItemsPanelTemplate>
|
||||||
|
</ItemsControl.ItemsPanel>
|
||||||
|
<ItemsControl.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Grid Padding="2" Opacity="{Binding Opacity}">
|
||||||
|
<TextBlock
|
||||||
|
Text="{Binding Name}"/>
|
||||||
|
<TextBlock
|
||||||
|
Text="{Binding Value}"
|
||||||
|
HorizontalAlignment="Right"/>
|
||||||
|
</Grid>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
|
||||||
<Rectangle Height="1" Grid.Row="3" Margin="0,6" Opacity="0.8">
|
<Rectangle Height="1" Grid.Row="3" Margin="0,6" Opacity="0.8">
|
||||||
<Rectangle.Fill>
|
<Rectangle.Fill>
|
||||||
|
|||||||
@@ -68,11 +68,13 @@
|
|||||||
<AppBarButton.Flyout>
|
<AppBarButton.Flyout>
|
||||||
<MenuFlyout Placement="Bottom">
|
<MenuFlyout Placement="Bottom">
|
||||||
<MenuFlyoutItem
|
<MenuFlyoutItem
|
||||||
Text="从 UIGF Json 文件导入"
|
Text="从 UIGF Json 文件导入"
|
||||||
Command="{Binding ImportFromUIGFJsonCommand}"/>
|
Command="{Binding ImportFromUIGFJsonCommand}"/>
|
||||||
<MenuFlyoutItem
|
<MenuFlyoutItem
|
||||||
Text="从 UIGF Excel 文件导入"
|
Text="从 UIGF Excel 文件导入"
|
||||||
Command="{Binding ImportFromUIGFExcelCommand}"/>
|
IsEnabled="False"
|
||||||
|
Visibility="Collapsed"
|
||||||
|
Command="{Binding ImportFromUIGFExcelCommand}"/>
|
||||||
</MenuFlyout>
|
</MenuFlyout>
|
||||||
</AppBarButton.Flyout>
|
</AppBarButton.Flyout>
|
||||||
</AppBarButton>
|
</AppBarButton>
|
||||||
@@ -80,11 +82,13 @@
|
|||||||
<AppBarButton.Flyout>
|
<AppBarButton.Flyout>
|
||||||
<MenuFlyout Placement="Bottom">
|
<MenuFlyout Placement="Bottom">
|
||||||
<MenuFlyoutItem
|
<MenuFlyoutItem
|
||||||
Text="导出到 UIGF Json 文件"
|
Text="导出到 UIGF Json 文件"
|
||||||
Command="{Binding ExportToUIGFJsonCommand}"/>
|
Command="{Binding ExportToUIGFJsonCommand}"/>
|
||||||
<MenuFlyoutItem
|
<MenuFlyoutItem
|
||||||
Text="导出到 UIGF Excel 文件"
|
Text="导出到 UIGF Excel 文件"
|
||||||
Command="{Binding ExportToUIGFExcelCommand}"/>
|
IsEnabled="False"
|
||||||
|
Visibility="Collapsed"
|
||||||
|
Command="{Binding ExportToUIGFExcelCommand}"/>
|
||||||
</MenuFlyout>
|
</MenuFlyout>
|
||||||
</AppBarButton.Flyout>
|
</AppBarButton.Flyout>
|
||||||
</AppBarButton>
|
</AppBarButton>
|
||||||
|
|||||||
@@ -95,6 +95,15 @@
|
|||||||
<Button Content="打开" Command="{Binding Experimental.OpenCacheFolderCommand}"/>
|
<Button Content="打开" Command="{Binding Experimental.OpenCacheFolderCommand}"/>
|
||||||
</sc:Setting.ActionContent>
|
</sc:Setting.ActionContent>
|
||||||
</sc:Setting>
|
</sc:Setting>
|
||||||
|
|
||||||
|
<sc:Setting
|
||||||
|
Icon=""
|
||||||
|
Header="上传深渊数据"
|
||||||
|
Description="将当前账号的深渊数据上传到胡桃数据库">
|
||||||
|
<sc:Setting.ActionContent>
|
||||||
|
<Button Content="上传" Command="{Binding Experimental.UploadSpiralAbyssRecordCommand}"/>
|
||||||
|
</sc:Setting.ActionContent>
|
||||||
|
</sc:Setting>
|
||||||
</sc:SettingsGroup>
|
</sc:SettingsGroup>
|
||||||
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|||||||
@@ -4,6 +4,10 @@
|
|||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using Snap.Hutao.Context.FileSystem.Location;
|
using Snap.Hutao.Context.FileSystem.Location;
|
||||||
using Snap.Hutao.Factory.Abstraction;
|
using Snap.Hutao.Factory.Abstraction;
|
||||||
|
using Snap.Hutao.Service.Abstraction;
|
||||||
|
using Snap.Hutao.Service.User;
|
||||||
|
using Snap.Hutao.Web.Hutao;
|
||||||
|
using Snap.Hutao.Web.Hutao.Model.Post;
|
||||||
using Windows.Storage;
|
using Windows.Storage;
|
||||||
using Windows.System;
|
using Windows.System;
|
||||||
|
|
||||||
@@ -22,8 +26,6 @@ internal class ExperimentalFeaturesViewModel : ObservableObject
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="asyncRelayCommandFactory">异步命令工厂</param>
|
/// <param name="asyncRelayCommandFactory">异步命令工厂</param>
|
||||||
/// <param name="hutaoLocation">数据文件夹</param>
|
/// <param name="hutaoLocation">数据文件夹</param>
|
||||||
/// <param name="signService">签到客户端</param>
|
|
||||||
/// <param name="infoBarService">信息条服务</param>
|
|
||||||
public ExperimentalFeaturesViewModel(
|
public ExperimentalFeaturesViewModel(
|
||||||
IAsyncRelayCommandFactory asyncRelayCommandFactory,
|
IAsyncRelayCommandFactory asyncRelayCommandFactory,
|
||||||
HutaoLocation hutaoLocation)
|
HutaoLocation hutaoLocation)
|
||||||
@@ -32,6 +34,7 @@ internal class ExperimentalFeaturesViewModel : ObservableObject
|
|||||||
|
|
||||||
OpenCacheFolderCommand = asyncRelayCommandFactory.Create(OpenCacheFolderAsync);
|
OpenCacheFolderCommand = asyncRelayCommandFactory.Create(OpenCacheFolderAsync);
|
||||||
OpenDataFolderCommand = asyncRelayCommandFactory.Create(OpenDataFolderAsync);
|
OpenDataFolderCommand = asyncRelayCommandFactory.Create(OpenDataFolderAsync);
|
||||||
|
UploadSpiralAbyssRecordCommand = asyncRelayCommandFactory.Create(UploadSpiralAbyssRecordAsync);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -44,6 +47,11 @@ internal class ExperimentalFeaturesViewModel : ObservableObject
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public ICommand OpenDataFolderCommand { get; }
|
public ICommand OpenDataFolderCommand { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 上传深渊记录命令
|
||||||
|
/// </summary>
|
||||||
|
public ICommand UploadSpiralAbyssRecordCommand { get; }
|
||||||
|
|
||||||
private Task OpenCacheFolderAsync()
|
private Task OpenCacheFolderAsync()
|
||||||
{
|
{
|
||||||
return Launcher.LaunchFolderAsync(ApplicationData.Current.TemporaryFolder).AsTask();
|
return Launcher.LaunchFolderAsync(ApplicationData.Current.TemporaryFolder).AsTask();
|
||||||
@@ -53,4 +61,22 @@ internal class ExperimentalFeaturesViewModel : ObservableObject
|
|||||||
{
|
{
|
||||||
return Launcher.LaunchFolderPathAsync(hutaoLocation.GetPath()).AsTask();
|
return Launcher.LaunchFolderPathAsync(hutaoLocation.GetPath()).AsTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task UploadSpiralAbyssRecordAsync()
|
||||||
|
{
|
||||||
|
HomaClient homaClient = Ioc.Default.GetRequiredService<HomaClient>();
|
||||||
|
IUserService userService = Ioc.Default.GetRequiredService<IUserService>();
|
||||||
|
|
||||||
|
if (userService.Current is Model.Binding.User user)
|
||||||
|
{
|
||||||
|
SimpleRecord record = await homaClient.GetPlayerRecordAsync(user).ConfigureAwait(false);
|
||||||
|
Web.Response.Response<string>? response = await homaClient.UploadRecordAsync(record).ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (response != null && response.IsOk())
|
||||||
|
{
|
||||||
|
IInfoBarService infoBarService = Ioc.Default.GetRequiredService<IInfoBarService>();
|
||||||
|
infoBarService.Success(response.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -51,7 +51,7 @@ internal static class ApiEndpoints
|
|||||||
/// <returns>游戏记录主页字符串</returns>
|
/// <returns>游戏记录主页字符串</returns>
|
||||||
public static string GameRecordIndex(string uid, string server)
|
public static string GameRecordIndex(string uid, string server)
|
||||||
{
|
{
|
||||||
return $"{ApiTakumiRecordApi}/index?role_id={uid}&server={server}";
|
return $"{ApiTakumiRecordApi}/index?server={server}&role_id={uid}";
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -29,7 +29,8 @@ internal abstract class DynamicSecretProvider2 : Md5Convert
|
|||||||
string b = postBody is null ? string.Empty : JsonSerializer.Serialize(postBody, options);
|
string b = postBody is null ? string.Empty : JsonSerializer.Serialize(postBody, options);
|
||||||
|
|
||||||
// query
|
// query
|
||||||
string q = string.Join('&', new UriBuilder(queryUrl).Query.Split('&').OrderBy(x => x));
|
string[] queries = queryUrl.Split('?', 2);
|
||||||
|
string q = queries.Length == 2 ? string.Join('&', queries[1].Split('&').OrderBy(x => x)) : string.Empty;
|
||||||
|
|
||||||
// check
|
// check
|
||||||
string check = ToHexString($"salt={Core.CoreEnvironment.DynamicSecret2Salt}&t={t}&r={r}&b={b}&q={q}").ToLowerInvariant();
|
string check = ToHexString($"salt={Core.CoreEnvironment.DynamicSecret2Salt}&t={t}&r={r}&b={b}&q={q}").ToLowerInvariant();
|
||||||
|
|||||||
@@ -55,6 +55,6 @@ internal class AnnouncementClient
|
|||||||
.GetFromJsonAsync<Response<ListWrapper<AnnouncementContent>>>(ApiEndpoints.AnnContent, jsonSerializerOptions, cancellationToken)
|
.GetFromJsonAsync<Response<ListWrapper<AnnouncementContent>>>(ApiEndpoints.AnnContent, jsonSerializerOptions, cancellationToken)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
return EnumerableExtensions.EmptyIfNull(resp?.Data?.List);
|
return EnumerableExtension.EmptyIfNull(resp?.Data?.List);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ public class GachaLogItem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[ExcelColumn(Name = "gacha_type")]
|
[ExcelColumn(Name = "gacha_type")]
|
||||||
[JsonPropertyName("gacha_type")]
|
[JsonPropertyName("gacha_type")]
|
||||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
[JsonConverter(typeof(EnumStringValueConverter<GachaConfigType>))]
|
||||||
public GachaConfigType GachaType { get; set; } = default!;
|
public GachaConfigType GachaType { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace Snap.Hutao.Web.Hoyolab;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public struct PlayerUid
|
public struct PlayerUid
|
||||||
{
|
{
|
||||||
private string? region = null;
|
private string? region = default;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构造一个新的玩家 Uid 结构
|
/// 构造一个新的玩家 Uid 结构
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
|
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
|
||||||
using Snap.Hutao.Extension;
|
|
||||||
using Snap.Hutao.Web.Hoyolab.Takumi.Binding;
|
using Snap.Hutao.Web.Hoyolab.Takumi.Binding;
|
||||||
using Snap.Hutao.Web.Response;
|
using Snap.Hutao.Web.Response;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
|||||||
@@ -45,6 +45,6 @@ internal class BindingClient
|
|||||||
.TryCatchGetFromJsonAsync<Response<ListWrapper<UserGameRole>>>(ApiEndpoints.UserGameRoles, options, logger, token)
|
.TryCatchGetFromJsonAsync<Response<ListWrapper<UserGameRole>>>(ApiEndpoints.UserGameRoles, options, logger, token)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
return EnumerableExtensions.EmptyIfNull(resp?.Data?.List);
|
return EnumerableExtension.EmptyIfNull(resp?.Data?.List);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ internal class GameRecordClient
|
|||||||
.TryCatchPostAsJsonAsync<Response<CharacterWrapper>>(logger, token)
|
.TryCatchPostAsJsonAsync<Response<CharacterWrapper>>(logger, token)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
return EnumerableExtensions.EmptyIfNull(resp?.Data?.Avatars);
|
return EnumerableExtension.EmptyIfNull(resp?.Data?.Avatars);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class CharacterData
|
private class CharacterData
|
||||||
|
|||||||
@@ -18,11 +18,11 @@ public class Offering
|
|||||||
/// 等级
|
/// 等级
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonPropertyName("level")]
|
[JsonPropertyName("level")]
|
||||||
public string Level { get; set; } = default!;
|
public int Level { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 图标
|
/// 图标
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonPropertyName("icon")]
|
[JsonPropertyName("icon")]
|
||||||
public string Icon { get; set; } = default!;
|
public Uri Icon { get; set; } = default!;
|
||||||
}
|
}
|
||||||
@@ -24,7 +24,7 @@ public class Floor
|
|||||||
/// 是否解锁
|
/// 是否解锁
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonPropertyName("is_unlock")]
|
[JsonPropertyName("is_unlock")]
|
||||||
public string IsUnlock { get; set; } = default!;
|
public bool IsUnlock { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 结束时间
|
/// 结束时间
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ public class WorldExploration
|
|||||||
/// 图标
|
/// 图标
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonPropertyName("icon")]
|
[JsonPropertyName("icon")]
|
||||||
public string Icon { get; set; } = default!;
|
public Uri Icon { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 名称
|
/// 名称
|
||||||
@@ -39,7 +39,8 @@ public class WorldExploration
|
|||||||
/// Reputation
|
/// Reputation
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonPropertyName("type")]
|
[JsonPropertyName("type")]
|
||||||
public string Type { get; set; } = default!;
|
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||||
|
public WorldExplorationType Type { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 供奉进度
|
/// 供奉进度
|
||||||
@@ -63,7 +64,7 @@ public class WorldExploration
|
|||||||
/// 地图链接
|
/// 地图链接
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonPropertyName("map_url")]
|
[JsonPropertyName("map_url")]
|
||||||
public string MapUrl { get; set; } = default!;
|
public Uri MapUrl { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 攻略链接 无攻略时为 <see cref="string.Empty"/>
|
/// 攻略链接 无攻略时为 <see cref="string.Empty"/>
|
||||||
@@ -75,41 +76,25 @@ public class WorldExploration
|
|||||||
/// 背景图片
|
/// 背景图片
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonPropertyName("background_image")]
|
[JsonPropertyName("background_image")]
|
||||||
public string BackgroundImage { get; set; } = default!;
|
public Uri BackgroundImage { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 反色图标
|
/// 反色图标
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonPropertyName("inner_icon")]
|
[JsonPropertyName("inner_icon")]
|
||||||
public string InnerIcon { get; set; } = default!;
|
public Uri InnerIcon { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 背景图片
|
/// 背景图片
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonPropertyName("cover")]
|
[JsonPropertyName("cover")]
|
||||||
public string Cover { get; set; } = default!;
|
public Uri Cover { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 百分比*100进度
|
/// 百分比*100进度
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double ExplorationPercentageBy10
|
public double ExplorationPercentageBy10
|
||||||
{
|
{
|
||||||
get => ExplorationPercentage / 10.0;
|
get => ExplorationPercentage / 1000.0;
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 类型名称转换器
|
|
||||||
/// </summary>
|
|
||||||
public string TypeFormatted
|
|
||||||
{
|
|
||||||
get => IsReputation ? "声望等级" : "供奉等级";
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 指示当前是否为声望
|
|
||||||
/// </summary>
|
|
||||||
public bool IsReputation
|
|
||||||
{
|
|
||||||
get => Type == "Reputation";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Web.Hoyolab.Takumi.GameRecord;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 世界探索类型
|
||||||
|
/// </summary>
|
||||||
|
public enum WorldExplorationType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 声望
|
||||||
|
/// </summary>
|
||||||
|
Reputation,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 供奉
|
||||||
|
/// </summary>
|
||||||
|
Offering,
|
||||||
|
}
|
||||||
205
src/Snap.Hutao/Snap.Hutao/Web/Hutao/HomaClient.cs
Normal file
205
src/Snap.Hutao/Snap.Hutao/Web/Hutao/HomaClient.cs
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
|
||||||
|
using Snap.Hutao.Extension;
|
||||||
|
using Snap.Hutao.Web.Hoyolab;
|
||||||
|
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord;
|
||||||
|
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Avatar;
|
||||||
|
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.SpiralAbyss;
|
||||||
|
using Snap.Hutao.Web.Hutao.Model;
|
||||||
|
using Snap.Hutao.Web.Hutao.Model.Post;
|
||||||
|
using Snap.Hutao.Web.Response;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Net.Http.Json;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Web.Hutao;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 胡桃API客户端
|
||||||
|
/// </summary>
|
||||||
|
// [Injection(InjectAs.Transient)]
|
||||||
|
[HttpClient(HttpClientConfigration.Default)]
|
||||||
|
internal class HomaClient
|
||||||
|
{
|
||||||
|
private const string HutaoAPI = "https://homa.snapgenshin.com";
|
||||||
|
|
||||||
|
private readonly HttpClient httpClient;
|
||||||
|
private readonly GameRecordClient gameRecordClient;
|
||||||
|
private readonly JsonSerializerOptions options;
|
||||||
|
private readonly ILogger<HomaClient> logger;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构造一个新的胡桃API客户端
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="httpClient">http客户端</param>
|
||||||
|
/// <param name="gameRecordClient">游戏记录客户端</param>
|
||||||
|
/// <param name="options">json序列化选项</param>
|
||||||
|
/// <param name="logger">日志器</param>
|
||||||
|
public HomaClient(HttpClient httpClient, GameRecordClient gameRecordClient, JsonSerializerOptions options, ILogger<HomaClient> logger)
|
||||||
|
{
|
||||||
|
this.httpClient = httpClient;
|
||||||
|
this.gameRecordClient = gameRecordClient;
|
||||||
|
this.options = options;
|
||||||
|
this.logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步检查对应的uid当前是否上传了数据
|
||||||
|
/// GET /Record/CheckRecord/{Uid}
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="uid">uid</param>
|
||||||
|
/// <param name="token">取消令牌</param>
|
||||||
|
/// <returns>当前是否上传了数据</returns>
|
||||||
|
public async Task<bool> CheckRecordUploadedAsync(PlayerUid uid, CancellationToken token = default)
|
||||||
|
{
|
||||||
|
Response<bool>? resp = await httpClient
|
||||||
|
.GetFromJsonAsync<Response<bool>>($"{HutaoAPI}/Record/Check?uid={uid}", token)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
return resp?.Data == true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步获取排行信息
|
||||||
|
/// GET /Record/Rank/{Uid}
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="uid">uid</param>
|
||||||
|
/// <param name="token">取消令牌</param>
|
||||||
|
/// <returns>排行信息</returns>
|
||||||
|
public async Task<RankInfo?> GetRankAsync(PlayerUid uid, CancellationToken token = default)
|
||||||
|
{
|
||||||
|
Response<RankInfo>? resp = await httpClient
|
||||||
|
.GetFromJsonAsync<Response<RankInfo>>($"{HutaoAPI}/Record/Rank?uid={uid}", token)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
return resp?.Data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步获取总览数据
|
||||||
|
/// GET /Statistics/Overview
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="token">取消令牌</param>
|
||||||
|
/// <returns>总览信息</returns>
|
||||||
|
public async Task<Overview?> GetOverviewAsync(CancellationToken token = default)
|
||||||
|
{
|
||||||
|
Response<Overview>? resp = await httpClient
|
||||||
|
.GetFromJsonAsync<Response<Overview>>($"{HutaoAPI}/Statistics/Overview", token)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
return resp?.Data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步获取角色出场率
|
||||||
|
/// GET /Statistics/Avatar/AttendanceRate
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="token">取消令牌</param>
|
||||||
|
/// <returns>角色出场率</returns>
|
||||||
|
public async Task<IEnumerable<AvatarAppearanceRank>> GetAvatarAttendanceRatesAsync(CancellationToken token = default)
|
||||||
|
{
|
||||||
|
Response<IEnumerable<AvatarAppearanceRank>>? resp = await httpClient
|
||||||
|
.GetFromJsonAsync<Response<IEnumerable<AvatarAppearanceRank>>>($"{HutaoAPI}/Statistics/Avatar/AttendanceRate", token)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
return EnumerableExtension.EmptyIfNull(resp?.Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步获取角色使用率
|
||||||
|
/// GET /Statistics/Avatar/UtilizationRate
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="token">取消令牌</param>
|
||||||
|
/// <returns>角色出场率</returns>
|
||||||
|
public async Task<IEnumerable<AvatarUsageRank>> GetAvatarUtilizationRatesAsync(CancellationToken token = default)
|
||||||
|
{
|
||||||
|
Response<IEnumerable<AvatarUsageRank>>? resp = await httpClient
|
||||||
|
.GetFromJsonAsync<Response<IEnumerable<AvatarUsageRank>>>($"{HutaoAPI}/Statistics/Avatar/UtilizationRate", token)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
return EnumerableExtension.EmptyIfNull(resp?.Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步获取角色/武器/圣遗物搭配
|
||||||
|
/// GET /Statistics/Avatar/AvatarCollocation
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="token">取消令牌</param>
|
||||||
|
/// <returns>角色/武器/圣遗物搭配</returns>
|
||||||
|
public async Task<IEnumerable<AvatarCollocation>> GetAvatarCollocationsAsync(CancellationToken token = default)
|
||||||
|
{
|
||||||
|
Response<IEnumerable<AvatarCollocation>>? resp = await httpClient
|
||||||
|
.GetFromJsonAsync<Response<IEnumerable<AvatarCollocation>>>($"{HutaoAPI}/Statistics/Avatar/AvatarCollocation", token)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
return EnumerableExtension.EmptyIfNull(resp?.Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步获取角色命座信息
|
||||||
|
/// GET /Statistics/Avatar/HoldingRate
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="token">取消令牌</param>
|
||||||
|
/// <returns>角色图片列表</returns>
|
||||||
|
public async Task<IEnumerable<AvatarConstellationInfo>> GetAvatarHoldingRatesAsync(CancellationToken token = default)
|
||||||
|
{
|
||||||
|
Response<IEnumerable<AvatarConstellationInfo>>? resp = await httpClient
|
||||||
|
.GetFromJsonAsync<Response<IEnumerable<AvatarConstellationInfo>>>($"{HutaoAPI}/Statistics/Avatar/HoldingRate", token)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
return EnumerableExtension.EmptyIfNull(resp?.Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步获取队伍出场次数
|
||||||
|
/// GET /Team/Combination
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="token">取消令牌</param>
|
||||||
|
/// <returns>队伍出场列表</returns>
|
||||||
|
public async Task<IEnumerable<TeamAppearance>> GetTeamCombinationsAsync(CancellationToken token = default)
|
||||||
|
{
|
||||||
|
Response<IEnumerable<TeamAppearance>>? resp = await httpClient
|
||||||
|
.GetFromJsonAsync<Response<IEnumerable<TeamAppearance>>>($"{HutaoAPI}/Team/Combination", token)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
return EnumerableExtension.EmptyIfNull(resp?.Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步获取角色的深渊记录
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="user">用户</param>
|
||||||
|
/// <param name="token">取消令牌</param>
|
||||||
|
/// <returns>玩家记录</returns>
|
||||||
|
public async Task<SimpleRecord> GetPlayerRecordAsync(Snap.Hutao.Model.Binding.User user, CancellationToken token = default)
|
||||||
|
{
|
||||||
|
PlayerInfo? playerInfo = await gameRecordClient
|
||||||
|
.GetPlayerInfoAsync(user, token)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
Must.NotNull(playerInfo!);
|
||||||
|
|
||||||
|
List<Character> characters = await gameRecordClient
|
||||||
|
.GetCharactersAsync(user, playerInfo, token)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
SpiralAbyss? spiralAbyssInfo = await gameRecordClient
|
||||||
|
.GetSpiralAbyssAsync(user, SpiralAbyssSchedule.Current, token)
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
Must.NotNull(spiralAbyssInfo!);
|
||||||
|
|
||||||
|
return new(Must.NotNull(user.SelectedUserGameRole!).GameUid, characters, spiralAbyssInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步上传记录
|
||||||
|
/// POST /Record/Upload
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="playerRecord">玩家记录</param>
|
||||||
|
/// <param name="token">取消令牌</param>
|
||||||
|
/// <returns>响应</returns>
|
||||||
|
public Task<Response<string>?> UploadRecordAsync(SimpleRecord playerRecord, CancellationToken token = default)
|
||||||
|
{
|
||||||
|
return httpClient.TryCatchPostAsJsonAsync<SimpleRecord, Response<string>>($"{HutaoAPI}/Record/Upload", playerRecord, options, logger, token);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,354 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
using Snap.Hutao.Core.Abstraction;
|
|
||||||
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
|
|
||||||
using Snap.Hutao.Extension;
|
|
||||||
using Snap.Hutao.Web.Hoyolab;
|
|
||||||
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord;
|
|
||||||
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Avatar;
|
|
||||||
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.SpiralAbyss;
|
|
||||||
using Snap.Hutao.Web.Hutao.Model;
|
|
||||||
using Snap.Hutao.Web.Hutao.Model.Post;
|
|
||||||
using Snap.Hutao.Web.Response;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Net.Http.Json;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Web.Hutao;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 胡桃API客户端
|
|
||||||
/// </summary>
|
|
||||||
// [Injection(InjectAs.Transient)]
|
|
||||||
[HttpClient(HttpClientConfigration.Default)]
|
|
||||||
internal class HutaoClient : ISupportAsyncInitialization
|
|
||||||
{
|
|
||||||
private const string AuthHost = "https://auth.snapgenshin.com";
|
|
||||||
private const string HutaoAPI = "https://hutao-api.snapgenshin.com";
|
|
||||||
|
|
||||||
private readonly HttpClient httpClient;
|
|
||||||
private readonly GameRecordClient gameRecordClient;
|
|
||||||
private readonly JsonSerializerOptions jsonSerializerOptions;
|
|
||||||
|
|
||||||
private bool isInitialized = false;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 构造一个新的胡桃API客户端
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="httpClient">http客户端</param>
|
|
||||||
/// <param name="gameRecordClient">游戏记录客户端</param>
|
|
||||||
/// <param name="jsonSerializerOptions">json序列化选项</param>
|
|
||||||
public HutaoClient(
|
|
||||||
HttpClient httpClient,
|
|
||||||
GameRecordClient gameRecordClient,
|
|
||||||
JsonSerializerOptions jsonSerializerOptions)
|
|
||||||
{
|
|
||||||
this.httpClient = httpClient;
|
|
||||||
this.gameRecordClient = gameRecordClient;
|
|
||||||
this.jsonSerializerOptions = jsonSerializerOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public bool IsInitialized { get => isInitialized; private set => isInitialized = value; }
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public async ValueTask<bool> InitializeAsync(CancellationToken token = default)
|
|
||||||
{
|
|
||||||
if (!IsInitialized)
|
|
||||||
{
|
|
||||||
Auth auth = new(
|
|
||||||
"08da6c59-da3b-48dd-8cf3-e3935a7f1d4f",
|
|
||||||
"ox5dwglSXYgenK2YBc8KrAVPoQbIJ4eHfUciE+05WfI=");
|
|
||||||
|
|
||||||
HttpResponseMessage response = await httpClient
|
|
||||||
.PostAsJsonAsync($"{AuthHost}/Auth/Login", auth, jsonSerializerOptions, token)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
Response<Token>? resp = await response.Content
|
|
||||||
.ReadFromJsonAsync<Response<Token>>(jsonSerializerOptions, token)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
httpClient.DefaultRequestHeaders.Authorization = new("Bearer", Must.NotNull(resp?.Data?.AccessToken!));
|
|
||||||
IsInitialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 异步检查对应的uid当前是否上传了数据
|
|
||||||
/// GET /Record/CheckRecord/{Uid}
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="uid">uid</param>
|
|
||||||
/// <param name="token">取消令牌</param>
|
|
||||||
/// <returns>当前是否上传了数据</returns>
|
|
||||||
public async Task<bool> CheckPeriodRecordUploadedAsync(PlayerUid uid, CancellationToken token = default)
|
|
||||||
{
|
|
||||||
Verify.Operation(IsInitialized, "必须在初始化后才能调用其他方法");
|
|
||||||
|
|
||||||
Response<UploadStatus>? resp = await httpClient
|
|
||||||
.GetFromJsonAsync<Response<UploadStatus>>($"{HutaoAPI}/Record/CheckRecord/{uid}", token)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
return resp is { Data: not null, Data.PeriodUploaded: true };
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 异步获取排行信息
|
|
||||||
/// GET /Record/Rank/{Uid}
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="uid">uid</param>
|
|
||||||
/// <param name="token">取消令牌</param>
|
|
||||||
/// <returns>排行信息</returns>
|
|
||||||
public async Task<RankInfoWrapper?> GetRankInfoAsync(PlayerUid uid, CancellationToken token = default)
|
|
||||||
{
|
|
||||||
Verify.Operation(IsInitialized, "必须在初始化后才能调用其他方法");
|
|
||||||
|
|
||||||
Response<RankInfoWrapper>? resp = await httpClient
|
|
||||||
.GetFromJsonAsync<Response<RankInfoWrapper>>($"{HutaoAPI}/Record/Rank/{uid}", token)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
return resp?.Data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 异步获取总览数据
|
|
||||||
/// GET /Statistics/Overview
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="token">取消令牌</param>
|
|
||||||
/// <returns>总览信息</returns>
|
|
||||||
public async Task<Overview?> GetOverviewAsync(CancellationToken token = default)
|
|
||||||
{
|
|
||||||
Verify.Operation(IsInitialized, "必须在初始化后才能调用其他方法");
|
|
||||||
|
|
||||||
Response<Overview>? resp = await httpClient
|
|
||||||
.GetFromJsonAsync<Response<Overview>>($"{HutaoAPI}/Statistics/Overview", token)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
return resp?.Data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 异步获取角色出场率
|
|
||||||
/// GET /Statistics/AvatarParticipation
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="token">取消令牌</param>
|
|
||||||
/// <returns>角色出场率</returns>
|
|
||||||
public async Task<IEnumerable<AvatarParticipation>> GetAvatarParticipationsAsync(CancellationToken token = default)
|
|
||||||
{
|
|
||||||
Verify.Operation(IsInitialized, "必须在初始化后才能调用其他方法");
|
|
||||||
|
|
||||||
Response<IEnumerable<AvatarParticipation>>? resp = await httpClient
|
|
||||||
.GetFromJsonAsync<Response<IEnumerable<AvatarParticipation>>>($"{HutaoAPI}/Statistics/AvatarParticipation", token)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
return EnumerableExtensions.EmptyIfNull(resp?.Data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 异步获取角色使用率
|
|
||||||
/// GET /Statistics2/AvatarParticipation
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="token">取消令牌</param>
|
|
||||||
/// <returns>角色出场率</returns>
|
|
||||||
public async Task<IEnumerable<AvatarParticipation>> GetAvatarParticipations2Async(CancellationToken token = default)
|
|
||||||
{
|
|
||||||
Verify.Operation(IsInitialized, "必须在初始化后才能调用其他方法");
|
|
||||||
|
|
||||||
Response<IEnumerable<AvatarParticipation>>? resp = await httpClient
|
|
||||||
.GetFromJsonAsync<Response<IEnumerable<AvatarParticipation>>>($"{HutaoAPI}/Statistics2/AvatarParticipation", token)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
return EnumerableExtensions.EmptyIfNull(resp?.Data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 异步获取角色圣遗物搭配
|
|
||||||
/// GET /Statistics/AvatarReliquaryUsage
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="token">取消令牌</param>
|
|
||||||
/// <returns>角色圣遗物搭配</returns>
|
|
||||||
public async Task<IEnumerable<AvatarReliquaryUsage>> GetAvatarReliquaryUsagesAsync(CancellationToken token = default)
|
|
||||||
{
|
|
||||||
Verify.Operation(IsInitialized, "必须在初始化后才能调用其他方法");
|
|
||||||
|
|
||||||
Response<IEnumerable<AvatarReliquaryUsage>>? resp = await httpClient
|
|
||||||
.GetFromJsonAsync<Response<IEnumerable<AvatarReliquaryUsage>>>($"{HutaoAPI}/Statistics/AvatarReliquaryUsage", token)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
return EnumerableExtensions.EmptyIfNull(resp?.Data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 异步获取角色搭配数据
|
|
||||||
/// GET /Statistics/TeamCollocation
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="token">取消令牌</param>
|
|
||||||
/// <returns>角色搭配数据</returns>
|
|
||||||
public async Task<IEnumerable<TeamCollocation>> GetTeamCollocationsAsync(CancellationToken token = default)
|
|
||||||
{
|
|
||||||
Verify.Operation(IsInitialized, "必须在初始化后才能调用其他方法");
|
|
||||||
|
|
||||||
Response<IEnumerable<TeamCollocation>>? resp = await httpClient
|
|
||||||
.GetFromJsonAsync<Response<IEnumerable<TeamCollocation>>>($"{HutaoAPI}/Statistics/TeamCollocation", token)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
return EnumerableExtensions.EmptyIfNull(resp?.Data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 异步获取角色武器搭配数据
|
|
||||||
/// GET /Statistics/AvatarWEaponUsage
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="token">取消令牌</param>
|
|
||||||
/// <returns>角色武器搭配数据</returns>
|
|
||||||
public async Task<IEnumerable<AvatarWeaponUsage>> GetAvatarWeaponUsagesAsync(CancellationToken token = default)
|
|
||||||
{
|
|
||||||
Verify.Operation(IsInitialized, "必须在初始化后才能调用其他方法");
|
|
||||||
|
|
||||||
Response<IEnumerable<AvatarWeaponUsage>>? resp = await httpClient
|
|
||||||
.GetFromJsonAsync<Response<IEnumerable<AvatarWeaponUsage>>>($"{HutaoAPI}/Statistics/AvatarWeaponUsage", token)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
return EnumerableExtensions.EmptyIfNull(resp?.Data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 异步获取角色命座信息
|
|
||||||
/// GET /Statistics/Constellation
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="token">取消令牌</param>
|
|
||||||
/// <returns>角色图片列表</returns>
|
|
||||||
public async Task<IEnumerable<AvatarConstellation>> GetAvatarConstellationsAsync(CancellationToken token = default)
|
|
||||||
{
|
|
||||||
Verify.Operation(IsInitialized, "必须在初始化后才能调用其他方法");
|
|
||||||
|
|
||||||
Response<IEnumerable<AvatarConstellation>>? resp = await httpClient
|
|
||||||
.GetFromJsonAsync<Response<IEnumerable<AvatarConstellation>>>($"{HutaoAPI}/Statistics/Constellation", token)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
return EnumerableExtensions.EmptyIfNull(resp?.Data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 异步获取队伍出场次数 层间
|
|
||||||
/// GET /Statistics/TeamCombination
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="token">取消令牌</param>
|
|
||||||
/// <returns>队伍出场列表</returns>
|
|
||||||
public async Task<IEnumerable<TeamCombination>> GetTeamCombinationsAsync(CancellationToken token = default)
|
|
||||||
{
|
|
||||||
Verify.Operation(IsInitialized, "必须在初始化后才能调用其他方法");
|
|
||||||
|
|
||||||
Response<IEnumerable<TeamCombination>>? resp = await httpClient
|
|
||||||
.GetFromJsonAsync<Response<IEnumerable<TeamCombination>>>($"{HutaoAPI}/Statistics/TeamCombination", token)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
return EnumerableExtensions.EmptyIfNull(resp?.Data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 异步获取队伍出场次数 层
|
|
||||||
/// GET /Statistics2/TeamCombination
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="token">取消令牌</param>
|
|
||||||
/// <returns>队伍出场列表</returns>
|
|
||||||
public async Task<IEnumerable<TeamCombination2>> GetTeamCombinations2Async(CancellationToken token = default)
|
|
||||||
{
|
|
||||||
Verify.Operation(IsInitialized, "必须在初始化后才能调用其他方法");
|
|
||||||
|
|
||||||
Response<IEnumerable<TeamCombination2>>? resp = await httpClient
|
|
||||||
.GetFromJsonAsync<Response<IEnumerable<TeamCombination2>>>($"{HutaoAPI}/Statistics2/TeamCombination", token)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
return EnumerableExtensions.EmptyIfNull(resp?.Data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 异步按角色列表异步获取推荐队伍
|
|
||||||
/// POST /Statistics2/TeamRecommanded
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="floor">楼层</param>
|
|
||||||
/// <param name="avatarIds">期望的角色,按期望出现顺序排序</param>
|
|
||||||
/// <param name="token">取消令牌</param>
|
|
||||||
/// <returns>队伍出场列表</returns>
|
|
||||||
public async Task<IEnumerable<TeamCombination2>> GetRecommandedTeamCombination2sAsync(int floor, IEnumerable<string> avatarIds, CancellationToken token = default)
|
|
||||||
{
|
|
||||||
Verify.Operation(IsInitialized, "必须在初始化后才能调用其他方法");
|
|
||||||
|
|
||||||
DesiredInfo desiredInfo = new(floor, avatarIds);
|
|
||||||
|
|
||||||
HttpResponseMessage response = await httpClient
|
|
||||||
.PostAsJsonAsync($"{HutaoAPI}/Statistics2/TeamRecommanded", desiredInfo, jsonSerializerOptions, token)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
Response<IEnumerable<TeamCombination2>>? resp = await response.Content
|
|
||||||
.ReadFromJsonAsync<Response<IEnumerable<TeamCombination2>>>(jsonSerializerOptions, token)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
return EnumerableExtensions.EmptyIfNull(resp?.Data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 异步获取角色的深渊记录
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="user">用户</param>
|
|
||||||
/// <param name="token">取消令牌</param>
|
|
||||||
/// <returns>玩家记录</returns>
|
|
||||||
public async Task<PlayerRecord> GetPlayerRecordAsync(Snap.Hutao.Model.Binding.User user, CancellationToken token = default)
|
|
||||||
{
|
|
||||||
PlayerInfo? playerInfo = await gameRecordClient
|
|
||||||
.GetPlayerInfoAsync(user, token)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
Must.NotNull(playerInfo!);
|
|
||||||
|
|
||||||
List<Character> characters = await gameRecordClient
|
|
||||||
.GetCharactersAsync(user, playerInfo, token)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
SpiralAbyss? spiralAbyssInfo = await gameRecordClient
|
|
||||||
.GetSpiralAbyssAsync(user, SpiralAbyssSchedule.Current, token)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
Must.NotNull(spiralAbyssInfo!);
|
|
||||||
|
|
||||||
return PlayerRecord.Create(Must.NotNull(user.SelectedUserGameRole!).GameUid, characters, spiralAbyssInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 异步上传记录
|
|
||||||
/// POST /Record/Upload
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="playerRecord">玩家记录</param>
|
|
||||||
/// <param name="token">取消令牌</param>
|
|
||||||
/// <returns>响应</returns>
|
|
||||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
||||||
internal async Task<Response<string>?> UploadRecordAsync(PlayerRecord playerRecord, CancellationToken token = default)
|
|
||||||
{
|
|
||||||
Verify.Operation(IsInitialized, "必须在初始化后才能调用其他方法");
|
|
||||||
|
|
||||||
HttpResponseMessage response = await httpClient
|
|
||||||
.PostAsJsonAsync($"{HutaoAPI}/Record/Upload", playerRecord, jsonSerializerOptions, token)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
return await response.Content
|
|
||||||
.ReadFromJsonAsync<Response<string>>(jsonSerializerOptions, token)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class Auth
|
|
||||||
{
|
|
||||||
public Auth(string appid, string secret)
|
|
||||||
{
|
|
||||||
Appid = appid;
|
|
||||||
Secret = secret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Appid { get; }
|
|
||||||
|
|
||||||
public string Secret { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
private class Token
|
|
||||||
{
|
|
||||||
public string AccessToken { get; } = default!;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,17 +4,17 @@
|
|||||||
namespace Snap.Hutao.Web.Hutao.Model;
|
namespace Snap.Hutao.Web.Hutao.Model;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 出场数据
|
/// 出场率
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class AvatarParticipation
|
public class AvatarAppearanceRank
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 层
|
/// 楼层
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Floor { get; set; }
|
public int Floor { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 角色比率
|
/// 排行
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IEnumerable<Rate<int>> AvatarUsage { get; set; } = default!;
|
public List<ItemRate<int, double>> Ranks { get; set; } = default!;
|
||||||
}
|
}
|
||||||
15
src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/AvatarBuild.cs
Normal file
15
src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/AvatarBuild.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Web.Hutao.Model;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 角色相关解构
|
||||||
|
/// </summary>
|
||||||
|
public abstract class AvatarBuild
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 角色Id
|
||||||
|
/// </summary>
|
||||||
|
public int AvatarId { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Web.Hutao.Model;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 角色搭配
|
||||||
|
/// </summary>
|
||||||
|
public class AvatarCollocation : AvatarBuild
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 其他角色
|
||||||
|
/// </summary>
|
||||||
|
public List<ItemRate<int, double>> Avatars { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 武器
|
||||||
|
/// </summary>
|
||||||
|
public List<ItemRate<int, double>> Weapons { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 圣遗物
|
||||||
|
/// </summary>
|
||||||
|
public List<ItemRate<ReliquarySets, double>> Reliquaries { get; set; } = default!;
|
||||||
|
}
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Web.Hutao.Model;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 命座比例
|
|
||||||
/// </summary>
|
|
||||||
public class AvatarConstellation
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 角色ID
|
|
||||||
/// </summary>
|
|
||||||
public int Avatar { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 持有率
|
|
||||||
/// </summary>
|
|
||||||
public decimal HoldingRate { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 各命座比率
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<Rate<int>> Rate { get; set; } = default!;
|
|
||||||
}
|
|
||||||
@@ -4,18 +4,17 @@
|
|||||||
namespace Snap.Hutao.Web.Hutao.Model;
|
namespace Snap.Hutao.Web.Hutao.Model;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 比率
|
/// 角色命座信息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T"><see cref="Id"/> 的类型</typeparam>
|
public class AvatarConstellationInfo : AvatarBuild
|
||||||
public class Rate<T>
|
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 表示唯一标识符的实例
|
/// 持有率
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public T Id { get; set; } = default!;
|
public double HoldingRate { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 比率
|
/// 命之座
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public decimal Value { get; set; }
|
public List<ItemRate<int, double>> Constellations { get; set; } = default!;
|
||||||
}
|
}
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Web.Hutao.Model;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 圣遗物配置数据
|
|
||||||
/// </summary>
|
|
||||||
public class AvatarReliquaryUsage
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 角色Id
|
|
||||||
/// </summary>
|
|
||||||
public int Avatar { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 圣遗物比率
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<Rate<ReliquarySets>> ReliquaryUsage { get; set; } = default!;
|
|
||||||
}
|
|
||||||
@@ -4,17 +4,17 @@
|
|||||||
namespace Snap.Hutao.Web.Hutao.Model;
|
namespace Snap.Hutao.Web.Hutao.Model;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 带有层的间编号
|
/// 使用率
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class LevelInfo
|
public class AvatarUsageRank
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 层
|
/// 楼层
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Floor { get; set; }
|
public int Floor { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 上下半 0,1
|
/// 排行
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Index { get; set; }
|
public List<ItemRate<int, double>> Ranks { get; set; } = default!;
|
||||||
}
|
}
|
||||||
@@ -8,12 +8,14 @@ namespace Snap.Hutao.Web.Hutao.Model.Converter;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal class ReliquarySetsConverter : JsonConverter<ReliquarySets>
|
internal class ReliquarySetsConverter : JsonConverter<ReliquarySets>
|
||||||
{
|
{
|
||||||
|
private const char Separator = ',';
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override ReliquarySets? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
public override ReliquarySets? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
{
|
{
|
||||||
if (reader.GetString() is string source)
|
if (reader.GetString() is string source)
|
||||||
{
|
{
|
||||||
string[] sets = source.Split(';');
|
string[] sets = source.Split(Separator);
|
||||||
return new(sets.Select(set => new ReliquarySet(set)));
|
return new(sets.Select(set => new ReliquarySet(set)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -25,6 +27,6 @@ internal class ReliquarySetsConverter : JsonConverter<ReliquarySets>
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override void Write(Utf8JsonWriter writer, ReliquarySets value, JsonSerializerOptions options)
|
public override void Write(Utf8JsonWriter writer, ReliquarySets value, JsonSerializerOptions options)
|
||||||
{
|
{
|
||||||
writer.WriteStringValue(string.Join(';', value));
|
writer.WriteStringValue(string.Join(Separator, value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Web.Hutao.Model;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 胡桃数据库物品
|
|
||||||
/// </summary>
|
|
||||||
public class Item
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 构造一个新的胡桃数据库物品
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">物品Id</param>
|
|
||||||
/// <param name="name">名称</param>
|
|
||||||
/// <param name="url">链接</param>
|
|
||||||
[JsonConstructor]
|
|
||||||
public Item(int id, string name, string url)
|
|
||||||
{
|
|
||||||
Id = id;
|
|
||||||
Name = name;
|
|
||||||
Url = url;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 物品Id
|
|
||||||
/// </summary>
|
|
||||||
public int Id { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 名称
|
|
||||||
/// </summary>
|
|
||||||
public string Name { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 链接
|
|
||||||
/// </summary>
|
|
||||||
public string Url { get; }
|
|
||||||
}
|
|
||||||
33
src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/ItemRate.cs
Normal file
33
src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/ItemRate.cs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Web.Hutao.Model;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 物品与率
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TItem">物品类型</typeparam>
|
||||||
|
/// <typeparam name="TRate">率类型</typeparam>
|
||||||
|
public class ItemRate<TItem, TRate>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 构造一个新的物品与率
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">物品</param>
|
||||||
|
/// <param name="rate">率</param>
|
||||||
|
public ItemRate(TItem item, TRate rate)
|
||||||
|
{
|
||||||
|
Item = item;
|
||||||
|
Rate = rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 物品
|
||||||
|
/// </summary>
|
||||||
|
public TItem Item { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 率
|
||||||
|
/// </summary>
|
||||||
|
public TRate Rate { get; set; }
|
||||||
|
}
|
||||||
@@ -9,17 +9,22 @@ namespace Snap.Hutao.Web.Hutao.Model;
|
|||||||
public class Overview
|
public class Overview
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 所有用户数量
|
/// 规划Id
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int TotalPlayerCount { get; set; }
|
public int ScheduleId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 当期提交深渊数据用户数量
|
/// 总记录数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int CollectedPlayerCount { get; set; }
|
public int RecordTotal { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 当期满星用户数量
|
/// 总深渊计数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int FullStarPlayerCount { get; set; }
|
public int SpiralAbyssTotal { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 满星数
|
||||||
|
/// </summary>
|
||||||
|
public int SpiralAbyssFullStar { get; set; }
|
||||||
}
|
}
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Web.Hutao.Model.Post;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 角色圣遗物套装
|
|
||||||
/// </summary>
|
|
||||||
public class AvatarReliquarySet
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 构造一个新的角色圣遗物套装
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">套装Id</param>
|
|
||||||
/// <param name="count">个数</param>
|
|
||||||
public AvatarReliquarySet(int id, int count)
|
|
||||||
{
|
|
||||||
Id = id;
|
|
||||||
Count = count;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 构造一个新的角色圣遗物套装
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="kvp">键值对</param>
|
|
||||||
public AvatarReliquarySet(KeyValuePair<int, int> kvp)
|
|
||||||
: this(kvp.Key, kvp.Value)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 套装Id
|
|
||||||
/// </summary>
|
|
||||||
public int Id { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 个数
|
|
||||||
/// </summary>
|
|
||||||
public int Count { get; }
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Web.Hutao.Model.Post;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 角色武器
|
|
||||||
/// </summary>
|
|
||||||
public class AvatarWeapon
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 构造一个新的角色武器
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">武器Id</param>
|
|
||||||
/// <param name="level">武器等级</param>
|
|
||||||
/// <param name="affixLevel">精炼等级</param>
|
|
||||||
public AvatarWeapon(int id, int level, int affixLevel)
|
|
||||||
{
|
|
||||||
Id = id;
|
|
||||||
Level = level;
|
|
||||||
AffixLevel = affixLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 武器等级
|
|
||||||
/// </summary>
|
|
||||||
public int Id { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 武器等级
|
|
||||||
/// </summary>
|
|
||||||
public int Level { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 精炼
|
|
||||||
/// </summary>
|
|
||||||
public int AffixLevel { get; }
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Web.Hutao.Model.Post;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 封装期望楼层与角色列表
|
|
||||||
/// </summary>
|
|
||||||
public class DesiredInfo
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 构造一个新的封装类
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="floor">楼层</param>
|
|
||||||
/// <param name="desiredAvatars">期望角色,按期望顺序排序</param>
|
|
||||||
public DesiredInfo(int floor, IEnumerable<string> desiredAvatars)
|
|
||||||
{
|
|
||||||
Floor = floor;
|
|
||||||
DesiredAvatars = desiredAvatars;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 层
|
|
||||||
/// </summary>
|
|
||||||
public int Floor { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 期望角色
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<string> DesiredAvatars { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Web.Hutao.Model.Post;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 原神物品包装器
|
|
||||||
/// </summary>
|
|
||||||
public class GenshinItemWrapper
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 构造一个新的原神物品包装器
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="avatars">角色</param>
|
|
||||||
/// <param name="weapons">武器</param>
|
|
||||||
/// <param name="reliquaries">圣遗物</param>
|
|
||||||
public GenshinItemWrapper(IEnumerable<Item> avatars, IEnumerable<Item> weapons, IEnumerable<Item> reliquaries)
|
|
||||||
{
|
|
||||||
Avatars = avatars;
|
|
||||||
Weapons = weapons;
|
|
||||||
Reliquaries = reliquaries;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 角色列表
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<Item> Avatars { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 武器列表
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<Item> Weapons { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 圣遗物列表
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<Item> Reliquaries { get; }
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.SpiralAbyss;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Web.Hutao.Model.Post;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 带有层信息的间
|
|
||||||
/// </summary>
|
|
||||||
internal class IndexedLevel
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 构造一个新的带有层信息的间
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="floorIndex">层号</param>
|
|
||||||
/// <param name="level">间信息</param>
|
|
||||||
public IndexedLevel(int floorIndex, Level level)
|
|
||||||
{
|
|
||||||
FloorIndex = floorIndex;
|
|
||||||
Level = level;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 层号
|
|
||||||
/// </summary>
|
|
||||||
public int FloorIndex { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 层信息
|
|
||||||
/// </summary>
|
|
||||||
public Level Level { get; }
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
using Snap.Hutao.Extension;
|
|
||||||
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Avatar;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Web.Hutao.Model.Post;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 玩家角色
|
|
||||||
/// </summary>
|
|
||||||
public class PlayerAvatar
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 构造一个新的玩家角色
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="avatar">角色</param>
|
|
||||||
internal PlayerAvatar(Character avatar)
|
|
||||||
{
|
|
||||||
Id = avatar.Id;
|
|
||||||
Level = avatar.Level;
|
|
||||||
ActivedConstellationNum = avatar.ActivedConstellationNum;
|
|
||||||
Weapon = new(avatar.Weapon.Id, avatar.Weapon.Level, avatar.Weapon.AffixLevel);
|
|
||||||
ReliquarySets = avatar.Reliquaries
|
|
||||||
.CountBy(relic => relic.ReliquarySet.Id)
|
|
||||||
.Select(kvp => new AvatarReliquarySet(kvp))
|
|
||||||
.ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 角色Id
|
|
||||||
/// </summary>
|
|
||||||
public int Id { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 角色等级
|
|
||||||
/// </summary>
|
|
||||||
public int Level { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 命座
|
|
||||||
/// </summary>
|
|
||||||
public int ActivedConstellationNum { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 武器
|
|
||||||
/// </summary>
|
|
||||||
public AvatarWeapon Weapon { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 圣遗物套装
|
|
||||||
/// </summary>
|
|
||||||
public List<AvatarReliquarySet> ReliquarySets { get; }
|
|
||||||
}
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Avatar;
|
|
||||||
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.SpiralAbyss;
|
|
||||||
using Snap.Hutao.Web.Response;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Web.Hutao.Model.Post;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 玩家记录
|
|
||||||
/// 使用 <see cref="CreateAsync(string, List{Character}, SpiralAbyss)"/> 来构建一个实例
|
|
||||||
/// </summary>
|
|
||||||
public class PlayerRecord
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 防止从外部构造一个新的玩家记录
|
|
||||||
/// </summary>
|
|
||||||
private PlayerRecord()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// uid
|
|
||||||
/// </summary>
|
|
||||||
public string Uid { get; private set; } = default!;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 玩家角色
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<PlayerAvatar> PlayerAvatars { get; private set; } = default!;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 玩家深渊信息
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<PlayerSpiralAbyssLevel> PlayerSpiralAbyssesLevels { get; private set; } = default!;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 造成最多伤害
|
|
||||||
/// </summary>
|
|
||||||
public Damage? DamageMost { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 承受最多伤害
|
|
||||||
/// </summary>
|
|
||||||
public Damage? TakeDamageMost { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 建造玩家记录
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="uid">玩家的uid</param>
|
|
||||||
/// <param name="detailAvatars">角色详情信息</param>
|
|
||||||
/// <param name="spiralAbyss">深渊信息</param>
|
|
||||||
/// <returns>玩家记录</returns>
|
|
||||||
internal static PlayerRecord Create(string uid, List<Character> detailAvatars, SpiralAbyss spiralAbyss)
|
|
||||||
{
|
|
||||||
IEnumerable<PlayerAvatar> playerAvatars = detailAvatars
|
|
||||||
.Select(avatar => new PlayerAvatar(avatar));
|
|
||||||
|
|
||||||
IEnumerable<PlayerSpiralAbyssLevel> playerSpiralAbyssLevels = spiralAbyss.Floors
|
|
||||||
.SelectMany(f => f.Levels, (f, level) => new IndexedLevel(f.Index, level))
|
|
||||||
.Select(indexedLevel => new PlayerSpiralAbyssLevel(indexedLevel));
|
|
||||||
|
|
||||||
return new()
|
|
||||||
{
|
|
||||||
Uid = uid,
|
|
||||||
PlayerAvatars = playerAvatars,
|
|
||||||
PlayerSpiralAbyssesLevels = playerSpiralAbyssLevels,
|
|
||||||
DamageMost = GetDamage(spiralAbyss.DamageRank),
|
|
||||||
TakeDamageMost = GetDamage(spiralAbyss.TakeDamageRank),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 上传记录
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="hutaoClient">使用的客户端</param>
|
|
||||||
/// <param name="token">取消令牌</param>
|
|
||||||
/// <returns>上传结果</returns>
|
|
||||||
internal Task<Response<string>?> UploadAsync(HutaoClient hutaoClient, CancellationToken token = default)
|
|
||||||
{
|
|
||||||
return hutaoClient.UploadRecordAsync(this, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Damage? GetDamage(List<Rank> ranks)
|
|
||||||
{
|
|
||||||
if (ranks.Count > 0)
|
|
||||||
{
|
|
||||||
Rank rank = ranks[0];
|
|
||||||
return new Damage(rank.AvatarId, rank.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Web.Hutao.Model.Post;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 玩家深渊战斗间信息
|
|
||||||
/// </summary>
|
|
||||||
public class PlayerSpiralAbyssLevel
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 构造一个新的玩家深渊战斗间信息
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="indexedLevel">楼层</param>
|
|
||||||
internal PlayerSpiralAbyssLevel(IndexedLevel indexedLevel)
|
|
||||||
{
|
|
||||||
FloorIndex = indexedLevel.FloorIndex;
|
|
||||||
LevelIndex = indexedLevel.Level.Index;
|
|
||||||
Star = indexedLevel.Level.Star;
|
|
||||||
Battles = indexedLevel.Level.Battles
|
|
||||||
.Select(battle => new PlayerSpiralAbyssBattle(battle));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 层号
|
|
||||||
/// </summary>
|
|
||||||
public int FloorIndex { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 间号
|
|
||||||
/// </summary>
|
|
||||||
public int LevelIndex { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 星数
|
|
||||||
/// </summary>
|
|
||||||
public int Star { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 战斗列表 分上下半间
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<PlayerSpiralAbyssBattle> Battles { get; }
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Avatar;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Web.Hutao.Model.Post;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 角色详情 角色
|
||||||
|
/// </summary>
|
||||||
|
public class SimpleAvatar
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 构造一个新的角色详情 角色
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="character">角色</param>
|
||||||
|
public SimpleAvatar(Character character)
|
||||||
|
{
|
||||||
|
AvatarId = character.Id;
|
||||||
|
WeaponId = character.Weapon.Id;
|
||||||
|
ReliquarySetIds = character.Reliquaries.Select(r => r.ReliquarySet.Id);
|
||||||
|
ActivedConstellationNumber = character.ActivedConstellationNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 角色 Id
|
||||||
|
/// </summary>
|
||||||
|
public int AvatarId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 武器 Id
|
||||||
|
/// </summary>
|
||||||
|
public int WeaponId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 圣遗物套装Id
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<int> ReliquarySetIds { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 命座
|
||||||
|
/// </summary>
|
||||||
|
public int ActivedConstellationNumber { get; set; }
|
||||||
|
}
|
||||||
@@ -6,27 +6,27 @@ using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.SpiralAbyss;
|
|||||||
namespace Snap.Hutao.Web.Hutao.Model.Post;
|
namespace Snap.Hutao.Web.Hutao.Model.Post;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 玩家深渊某间的战斗信息
|
/// 上下半信息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class PlayerSpiralAbyssBattle
|
public class SimpleBattle
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构造一个新的战斗信息
|
/// 构造一个新的战斗
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="battle">战斗</param>
|
/// <param name="battle">战斗</param>
|
||||||
internal PlayerSpiralAbyssBattle(Battle battle)
|
public SimpleBattle(Battle battle)
|
||||||
{
|
{
|
||||||
BattleIndex = battle.Index;
|
Index = battle.Index;
|
||||||
AvatarIds = battle.Avatars.Select(a => a.Id);
|
Avatars = battle.Avatars.Select(a => a.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 战斗上下半间 0,1
|
/// 上下半遍号 1-2
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int BattleIndex { get; }
|
public int Index { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 角色Id列表
|
/// 角色列表
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IEnumerable<int> AvatarIds { get; }
|
public IEnumerable<int> Avatars { get; set; } = default!;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.SpiralAbyss;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Web.Hutao.Model.Post;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 层信息
|
||||||
|
/// </summary>
|
||||||
|
public class SimpleFloor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 构造一个新的层信息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="floor">层信息</param>
|
||||||
|
public SimpleFloor(Floor floor)
|
||||||
|
{
|
||||||
|
Index = floor.Index;
|
||||||
|
Star = floor.Star;
|
||||||
|
Levels = floor.Levels.Select(l => new SimpleLevel(l));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 层遍号 1-12|9-12
|
||||||
|
/// </summary>
|
||||||
|
public int Index { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 星数
|
||||||
|
/// </summary>
|
||||||
|
public int Star { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 间
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<SimpleLevel> Levels { get; set; } = default!;
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.SpiralAbyss;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Web.Hutao.Model.Post;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 间信息
|
||||||
|
/// </summary>
|
||||||
|
public class SimpleLevel
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 构造一个新的间信息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="level">间信息</param>
|
||||||
|
public SimpleLevel(Level level)
|
||||||
|
{
|
||||||
|
Index = level.Index;
|
||||||
|
Star = level.Star;
|
||||||
|
Battles = level.Battles.Select(b => new SimpleBattle(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 间遍号 1-3
|
||||||
|
/// </summary>
|
||||||
|
public int Index { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 星数
|
||||||
|
/// </summary>
|
||||||
|
public int Star { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 上下半信息
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<SimpleBattle> Battles { get; set; } = default!;
|
||||||
|
}
|
||||||
@@ -1,22 +1,23 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.SpiralAbyss;
|
||||||
|
|
||||||
namespace Snap.Hutao.Web.Hutao.Model.Post;
|
namespace Snap.Hutao.Web.Hutao.Model.Post;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 伤害信息
|
/// 数值
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Damage
|
public class SimpleRank
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构造一个新的伤害信息
|
/// 构造一个新的数值
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="avatarId">角色Id</param>
|
/// <param name="rank">排行</param>
|
||||||
/// <param name="value">值</param>
|
public SimpleRank(Rank rank)
|
||||||
public Damage(int avatarId, int value)
|
|
||||||
{
|
{
|
||||||
AvatarId = avatarId;
|
AvatarId = rank.AvatarId;
|
||||||
Value = value;
|
Value = rank.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Avatar;
|
||||||
|
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.SpiralAbyss;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Web.Hutao.Model.Post;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 记录
|
||||||
|
/// </summary>
|
||||||
|
public class SimpleRecord
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 构造一个新的记录
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="uid">uid</param>
|
||||||
|
/// <param name="characters">详细的角色信息</param>
|
||||||
|
/// <param name="spiralAbyss">深渊信息</param>
|
||||||
|
public SimpleRecord(string uid, List<Character> characters, SpiralAbyss spiralAbyss)
|
||||||
|
{
|
||||||
|
Uid = uid;
|
||||||
|
Identity = "Snap Hutao";
|
||||||
|
SpiralAbyss = new(spiralAbyss);
|
||||||
|
Avatars = characters.Select(a => new SimpleAvatar(a));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Uid
|
||||||
|
/// </summary>
|
||||||
|
public string Uid { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 上传者身份
|
||||||
|
/// </summary>
|
||||||
|
public string Identity { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 深境螺旋
|
||||||
|
/// </summary>
|
||||||
|
public SimpleSpiralAbyss SpiralAbyss { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 角色
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<SimpleAvatar> Avatars { get; set; } = default!;
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.SpiralAbyss;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Web.Hutao.Model.Post;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 深渊数据
|
||||||
|
/// </summary>
|
||||||
|
public class SimpleSpiralAbyss
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 构造一个新的深渊信息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="spiralAbyss">深渊信息</param>
|
||||||
|
public SimpleSpiralAbyss(SpiralAbyss spiralAbyss)
|
||||||
|
{
|
||||||
|
ScheduleId = spiralAbyss.ScheduleId;
|
||||||
|
Damage = new(spiralAbyss.DamageRank.Single());
|
||||||
|
TakeDamage = new(spiralAbyss.TakeDamageRank.Single());
|
||||||
|
Floors = spiralAbyss.Floors.Select(f => new SimpleFloor(f));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 计划Id
|
||||||
|
/// </summary>
|
||||||
|
public int ScheduleId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 造成伤害
|
||||||
|
/// </summary>
|
||||||
|
public SimpleRank Damage { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 受到伤害
|
||||||
|
/// </summary>
|
||||||
|
public SimpleRank TakeDamage { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 层
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<SimpleFloor> Floors { get; set; } = default!;
|
||||||
|
}
|
||||||
@@ -4,27 +4,17 @@
|
|||||||
namespace Snap.Hutao.Web.Hutao.Model;
|
namespace Snap.Hutao.Web.Hutao.Model;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 排行信息
|
/// 排行包装
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class RankInfo
|
public class RankInfo
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 角色Id
|
/// 造成伤害
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int AvatarId { get; set; }
|
public ItemRate<int, double> Damage { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 值
|
/// 受到伤害
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Value { get; set; }
|
public ItemRate<int, double> TakeDamage { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 百分比
|
|
||||||
/// </summary>
|
|
||||||
public double Percent { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 总体百分比
|
|
||||||
/// </summary>
|
|
||||||
public double PercentTotal { get; set; }
|
|
||||||
}
|
}
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Web.Hutao.Model;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 排行包装
|
|
||||||
/// </summary>
|
|
||||||
public class RankInfoWrapper
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 伤害
|
|
||||||
/// </summary>
|
|
||||||
public RankInfo? Damage { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 承受伤害
|
|
||||||
/// </summary>
|
|
||||||
public RankInfo? TakeDamage { get; set; }
|
|
||||||
}
|
|
||||||
@@ -2,19 +2,18 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
namespace Snap.Hutao.Web.Hutao.Model;
|
namespace Snap.Hutao.Web.Hutao.Model;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 武器使用数据
|
/// 队伍出场次数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class AvatarWeaponUsage
|
public class TeamAppearance
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 角色Id
|
/// 上半
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Avatar { get; set; }
|
public List<ItemRate<string, int>> Up { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 武器比率
|
/// 下半
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IEnumerable<Rate<int>> Weapons { get; set; } = default!;
|
public List<ItemRate<string, int>> Down { get; set; } = default!;
|
||||||
}
|
}
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Web.Hutao.Model;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 组队数据
|
|
||||||
/// </summary>
|
|
||||||
public class TeamCollocation
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 角色Id
|
|
||||||
/// </summary>
|
|
||||||
public int Avatar { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 角色搭配比率
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<Rate<int>> Collocations { get; set; } = default!;
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Web.Hutao.Model;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 队伍上场率
|
|
||||||
/// 层间上场率
|
|
||||||
/// </summary>
|
|
||||||
public record TeamCombination
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 带有层的间
|
|
||||||
/// </summary>
|
|
||||||
public LevelInfo Level { get; set; } = null!;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 队伍
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<Rate<Team>> Teams { get; set; } = null!;
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Web.Hutao.Model;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 队伍上场率2
|
|
||||||
/// 层上场率
|
|
||||||
/// </summary>
|
|
||||||
public record TeamCombination2
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 带有层的间
|
|
||||||
/// </summary>
|
|
||||||
public int Floor { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 队伍
|
|
||||||
/// </summary>
|
|
||||||
public IEnumerable<Rate<Team>> Teams { get; set; } = null!;
|
|
||||||
}
|
|
||||||
@@ -40,16 +40,6 @@ public class Response : ISupportValidation
|
|||||||
[JsonPropertyName("message")]
|
[JsonPropertyName("message")]
|
||||||
public string Message { get; set; } = default!;
|
public string Message { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 响应是否正常
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="response">响应</param>
|
|
||||||
/// <returns>是否Ok</returns>
|
|
||||||
public static bool IsOk(Response? response)
|
|
||||||
{
|
|
||||||
return response is not null && response.ReturnCode == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public bool Validate()
|
public bool Validate()
|
||||||
{
|
{
|
||||||
@@ -89,6 +79,17 @@ public class Response<TData> : Response
|
|||||||
[JsonPropertyName("data")]
|
[JsonPropertyName("data")]
|
||||||
public TData? Data { get; set; }
|
public TData? Data { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 响应是否正常
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="response">响应</param>
|
||||||
|
/// <returns>是否Ok</returns>
|
||||||
|
[MemberNotNullWhen(true, nameof(Data))]
|
||||||
|
public bool IsOk()
|
||||||
|
{
|
||||||
|
return ReturnCode == 0;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ using Windows.Win32.System.Diagnostics.ToolHelp;
|
|||||||
namespace Snap.Hutao.Win32;
|
namespace Snap.Hutao.Win32;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 内存拓展 for <see cref="Memory{T}"/> <see cref="Span{T}"/>
|
/// 内存拓展 for <see cref="Memory{T}"/> and <see cref="Span{T}"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static class MemoryExtensions
|
internal static class MemoryExtensions
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Windows.Graphics;
|
using Windows.Graphics;
|
||||||
using Windows.Win32.System.Diagnostics.ToolHelp;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Win32;
|
namespace Snap.Hutao.Win32;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user