mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
migrate to metadata2
This commit is contained in:
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace Snap.Hutao.SourceGeneration.Identity;
|
namespace Snap.Hutao.SourceGeneration.Identity;
|
||||||
|
|
||||||
@@ -32,8 +33,6 @@ internal sealed class IdentityGenerator : IIncrementalGenerator
|
|||||||
|
|
||||||
if (identities.Any())
|
if (identities.Any())
|
||||||
{
|
{
|
||||||
GenerateIdentityConverter(context);
|
|
||||||
|
|
||||||
foreach (IdentityStructMetadata identityStruct in identities)
|
foreach (IdentityStructMetadata identityStruct in identities)
|
||||||
{
|
{
|
||||||
GenerateIdentityStruct(context, identityStruct);
|
GenerateIdentityStruct(context, identityStruct);
|
||||||
@@ -41,137 +40,157 @@ internal sealed class IdentityGenerator : IIncrementalGenerator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void GenerateIdentityConverter(SourceProductionContext context)
|
private static void GenerateIdentityStruct(SourceProductionContext context, IdentityStructMetadata metadata)
|
||||||
{
|
{
|
||||||
string source = $$"""
|
string name = metadata.Name;
|
||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.Primitive.Converter;
|
StringBuilder sourceBuilder = new StringBuilder().AppendLine($$"""
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Id 转换器
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="TWrapper">包装类型</typeparam>
|
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("{{nameof(IdentityGenerator)}}", "1.0.0.0")]
|
|
||||||
internal unsafe sealed class IdentityConverter<TWrapper> : JsonConverter<TWrapper>
|
|
||||||
where TWrapper : unmanaged
|
|
||||||
{
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override TWrapper Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
|
||||||
{
|
|
||||||
if (reader.TokenType == JsonTokenType.Number)
|
|
||||||
{
|
|
||||||
int value = reader.GetInt32();
|
|
||||||
return *(TWrapper*)&value;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new JsonException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override void Write(Utf8JsonWriter writer, TWrapper value, JsonSerializerOptions options)
|
|
||||||
{
|
|
||||||
writer.WriteNumberValue(*(int*)&value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
""";
|
|
||||||
|
|
||||||
context.AddSource("IdentityConverter.g.cs", source);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void GenerateIdentityStruct(SourceProductionContext context, IdentityStructMetadata identityStruct)
|
|
||||||
{
|
|
||||||
string name = identityStruct.Name;
|
|
||||||
string type = identityStruct.Type;
|
|
||||||
|
|
||||||
string source = $$"""
|
|
||||||
// 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.Model.Primitive.Converter;
|
using Snap.Hutao.Model.Primitive.Converter;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.Primitive;
|
namespace Snap.Hutao.Model.Primitive;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// {{identityStruct.Documentation}}
|
/// {{metadata.Documentation}}
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonConverter(typeof(IdentityConverter<{{name}}>))]
|
[JsonConverter(typeof(IdentityConverter<{{name}}>))]
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("{{nameof(IdentityGenerator)}}","1.0.0.0")]
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("{{nameof(IdentityGenerator)}}","1.0.0.0")]
|
||||||
internal readonly struct {{name}} : IEquatable<{{name}}>
|
internal readonly partial struct {{name}}
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 值
|
/// 值
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly {{type}} Value;
|
public readonly uint Value;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="{{name}}"/> struct.
|
/// Initializes a new instance of the <see cref="{{name}}"/> struct.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="value">value</param>
|
/// <param name="value">value</param>
|
||||||
public {{name}}({{type}} value)
|
public {{name}}(uint value)
|
||||||
{
|
{
|
||||||
Value = value;
|
Value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static implicit operator {{type}}({{name}} value)
|
public static implicit operator uint({{name}} value)
|
||||||
{
|
{
|
||||||
return value.Value;
|
return value.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static implicit operator {{name}}({{type}} value)
|
public static implicit operator {{name}}(uint value)
|
||||||
{
|
{
|
||||||
return new(value);
|
return new(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool operator ==({{name}} left, {{name}} right)
|
|
||||||
{
|
|
||||||
return left.Value == right.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator !=({{name}} left, {{name}} right)
|
|
||||||
{
|
|
||||||
return !(left == right);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public bool Equals({{name}} other)
|
|
||||||
{
|
|
||||||
return Value == other.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
return obj is {{name}} other && Equals(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
return Value.GetHashCode();
|
return Value.GetHashCode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
""";
|
""");
|
||||||
|
|
||||||
context.AddSource($"{name}.g.cs", source);
|
if (metadata.Equatable)
|
||||||
|
{
|
||||||
|
sourceBuilder.AppendLine($$"""
|
||||||
|
|
||||||
|
internal readonly partial struct {{name}} : IEquatable<{{name}}>
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
return obj is {{name}} other && Equals(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public bool Equals({{name}} other)
|
||||||
|
{
|
||||||
|
return Value == other.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (metadata.EqualityOperators)
|
||||||
|
{
|
||||||
|
sourceBuilder.AppendLine($$"""
|
||||||
|
|
||||||
|
internal readonly partial struct {{name}} : IEqualityOperators<{{name}}, {{name}}, bool>, IEqualityOperators<{{name}}, uint, bool>
|
||||||
|
{
|
||||||
|
public static bool operator ==({{name}} left, {{name}} right)
|
||||||
|
{
|
||||||
|
return left.Value == right.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==({{name}} left, uint right)
|
||||||
|
{
|
||||||
|
return left.Value == right;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=({{name}} left, {{name}} right)
|
||||||
|
{
|
||||||
|
return !(left == right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=({{name}} left, uint right)
|
||||||
|
{
|
||||||
|
return !(left == right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (metadata.AdditionOperators)
|
||||||
|
{
|
||||||
|
sourceBuilder.AppendLine($$"""
|
||||||
|
|
||||||
|
internal readonly partial struct {{name}} : IAdditionOperators<{{name}}, {{name}}, {{name}}>, IAdditionOperators<{{name}}, uint, {{name}}>
|
||||||
|
{
|
||||||
|
public static {{name}} operator +({{name}} left, {{name}} right)
|
||||||
|
{
|
||||||
|
return left.Value + right.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static {{name}} operator +({{name}} left, uint right)
|
||||||
|
{
|
||||||
|
return left.Value + right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (metadata.IncrementOperators)
|
||||||
|
{
|
||||||
|
sourceBuilder.AppendLine($$"""
|
||||||
|
|
||||||
|
internal readonly partial struct {{name}} : IIncrementOperators<{{name}}>
|
||||||
|
{
|
||||||
|
public static unsafe {{name}} operator ++({{name}} value)
|
||||||
|
{
|
||||||
|
++*(uint*)&value;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""");
|
||||||
|
}
|
||||||
|
|
||||||
|
context.AddSource($"{name}.g.cs", sourceBuilder.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
private sealed class IdentityStructMetadata
|
private sealed class IdentityStructMetadata
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// 名称
|
|
||||||
/// </summary>
|
|
||||||
public string Name { get; set; } = default!;
|
public string Name { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 基底类型
|
|
||||||
/// </summary>
|
|
||||||
public string Type { get; set; } = default!;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 文档
|
|
||||||
/// </summary>
|
|
||||||
public string? Documentation { get; set; }
|
public string? Documentation { get; set; }
|
||||||
|
|
||||||
|
public bool Equatable { get; set; }
|
||||||
|
|
||||||
|
public bool EqualityOperators { get; set; }
|
||||||
|
|
||||||
|
public bool AdditionOperators { get; set; }
|
||||||
|
|
||||||
|
public bool IncrementOperators { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Text.Json;
|
using System.Collections.Generic;
|
||||||
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
namespace Snap.Hutao.Test;
|
namespace Snap.Hutao.Test;
|
||||||
@@ -18,6 +19,13 @@ public class JsonSerializeTest
|
|||||||
}
|
}
|
||||||
""";
|
""";
|
||||||
|
|
||||||
|
private const string SmapleNumberDictionaryJson = """
|
||||||
|
{
|
||||||
|
"111" : "12",
|
||||||
|
"222" : "34"
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void DelegatePropertyCanSerialize()
|
public void DelegatePropertyCanSerialize()
|
||||||
{
|
{
|
||||||
@@ -26,11 +34,33 @@ public class JsonSerializeTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void EmptyStringCanSerializeAsNumber()
|
public void EmptyStringCannotSerializeAsNumber()
|
||||||
{
|
{
|
||||||
// Throw
|
bool caught = false;
|
||||||
StringNumberSample sample = JsonSerializer.Deserialize<StringNumberSample>(SmapleNumberObjectJson)!;
|
try
|
||||||
Assert.AreEqual(sample.A, 0);
|
{
|
||||||
|
// Throw
|
||||||
|
StringNumberSample sample = JsonSerializer.Deserialize<StringNumberSample>(SmapleNumberObjectJson)!;
|
||||||
|
Assert.AreEqual(sample.A, 0);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
caught = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.IsTrue(caught);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void NumberStringKeyCanSerializeAsKey()
|
||||||
|
{
|
||||||
|
JsonSerializerOptions options = new()
|
||||||
|
{
|
||||||
|
NumberHandling = JsonNumberHandling.AllowReadingFromString,
|
||||||
|
};
|
||||||
|
|
||||||
|
Dictionary<int,string> sample = JsonSerializer.Deserialize<Dictionary<int, string>>(SmapleNumberDictionaryJson, options)!;
|
||||||
|
Assert.AreEqual(sample[111], "12");
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Sample
|
private class Sample
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ internal sealed class UserdataCorruptedException : Exception
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="message">消息</param>
|
/// <param name="message">消息</param>
|
||||||
/// <param name="innerException">内部错误</param>
|
/// <param name="innerException">内部错误</param>
|
||||||
public UserdataCorruptedException(string message, Exception innerException)
|
public UserdataCorruptedException(string message, Exception? innerException)
|
||||||
: base(string.Format(SH.CoreExceptionServiceUserdataCorruptedMessage, $"{message}\n{innerException.Message}"), innerException)
|
: base(string.Format(SH.CoreExceptionServiceUserdataCorruptedMessage, $"{message}\n{innerException?.Message}"), innerException)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,39 +2,38 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Security.Cryptography;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Core.IO;
|
namespace Snap.Hutao.Core.IO.Hashing;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 摘要
|
/// 摘要
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HighQuality]
|
[HighQuality]
|
||||||
internal static class Digest
|
internal static class MD5
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步获取文件 Md5 摘要
|
/// 异步获取文件 MD5 摘要
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="filePath">文件路径</param>
|
/// <param name="filePath">文件路径</param>
|
||||||
/// <param name="token">取消令牌</param>
|
/// <param name="token">取消令牌</param>
|
||||||
/// <returns>文件 Md5 摘要</returns>
|
/// <returns>文件 Md5 摘要</returns>
|
||||||
public static async Task<string> GetFileMD5Async(string filePath, CancellationToken token = default)
|
public static async Task<string> HashFileAsync(string filePath, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
using (FileStream stream = File.OpenRead(filePath))
|
using (FileStream stream = File.OpenRead(filePath))
|
||||||
{
|
{
|
||||||
return await GetStreamMD5Async(stream, token).ConfigureAwait(false);
|
return await HashAsync(stream, token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取流的 Md5 摘要
|
/// 获取流的 MD5 摘要
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="stream">流</param>
|
/// <param name="stream">流</param>
|
||||||
/// <param name="token">取消令牌</param>
|
/// <param name="token">取消令牌</param>
|
||||||
/// <returns>流 Md5 摘要</returns>
|
/// <returns>流 Md5 摘要</returns>
|
||||||
public static async Task<string> GetStreamMD5Async(Stream stream, CancellationToken token = default)
|
public static async Task<string> HashAsync(Stream stream, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
using (MD5 md5 = MD5.Create())
|
using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create())
|
||||||
{
|
{
|
||||||
byte[] bytes = await md5.ComputeHashAsync(stream, token).ConfigureAwait(false);
|
byte[] bytes = await md5.ComputeHashAsync(stream, token).ConfigureAwait(false);
|
||||||
return System.Convert.ToHexString(bytes);
|
return System.Convert.ToHexString(bytes);
|
||||||
41
src/Snap.Hutao/Snap.Hutao/Core/IO/Hashing/XXH64.cs
Normal file
41
src/Snap.Hutao/Snap.Hutao/Core/IO/Hashing/XXH64.cs
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
|
using System.IO.Hashing;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Core.IO.Hashing;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// XXH64 摘要
|
||||||
|
/// </summary>
|
||||||
|
internal static class XXH64
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 获取流的 XXH64 摘要
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">流</param>
|
||||||
|
/// <param name="token">取消令牌</param>
|
||||||
|
/// <returns>摘要</returns>
|
||||||
|
public static async Task<string> HashAsync(Stream stream, CancellationToken token = default)
|
||||||
|
{
|
||||||
|
XxHash64 xxHash64 = new();
|
||||||
|
await xxHash64.AppendAsync(stream, token).ConfigureAwait(false);
|
||||||
|
byte[] bytes = xxHash64.GetHashAndReset();
|
||||||
|
return System.Convert.ToHexString(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取文件的 XXH64 摘要
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">路径</param>
|
||||||
|
/// <param name="token">取消令牌</param>
|
||||||
|
/// <returns>摘要</returns>
|
||||||
|
public static async Task<string> HashFileAsync(string path, CancellationToken token = default)
|
||||||
|
{
|
||||||
|
using (FileStream stream = File.OpenRead(path))
|
||||||
|
{
|
||||||
|
return await HashAsync(stream, token).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,6 +20,7 @@ internal static class JsonOptions
|
|||||||
ReadCommentHandling = JsonCommentHandling.Skip,
|
ReadCommentHandling = JsonCommentHandling.Skip,
|
||||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
|
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
|
||||||
|
NumberHandling = JsonNumberHandling.AllowReadingFromString,
|
||||||
PropertyNameCaseInsensitive = true,
|
PropertyNameCaseInsensitive = true,
|
||||||
WriteIndented = true,
|
WriteIndented = true,
|
||||||
TypeInfoResolver = new DefaultJsonTypeInfoResolver()
|
TypeInfoResolver = new DefaultJsonTypeInfoResolver()
|
||||||
|
|||||||
@@ -1,6 +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.
|
||||||
|
|
||||||
|
using System.Numerics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
@@ -15,10 +16,12 @@ internal static partial class EnumerableExtension
|
|||||||
/// 增加计数
|
/// 增加计数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TKey">键类型</typeparam>
|
/// <typeparam name="TKey">键类型</typeparam>
|
||||||
|
/// <typeparam name="TValue">值类型</typeparam>
|
||||||
/// <param name="dict">字典</param>
|
/// <param name="dict">字典</param>
|
||||||
/// <param name="key">键</param>
|
/// <param name="key">键</param>
|
||||||
public static void Increase<TKey>(this Dictionary<TKey, int> dict, TKey key)
|
public static void IncreaseOne<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key)
|
||||||
where TKey : notnull
|
where TKey : notnull
|
||||||
|
where TValue : struct, IIncrementOperators<TValue>
|
||||||
{
|
{
|
||||||
++CollectionsMarshal.GetValueRefOrAddDefault(dict, key, out _);
|
++CollectionsMarshal.GetValueRefOrAddDefault(dict, key, out _);
|
||||||
}
|
}
|
||||||
@@ -27,14 +30,16 @@ internal static partial class EnumerableExtension
|
|||||||
/// 增加计数
|
/// 增加计数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TKey">键类型</typeparam>
|
/// <typeparam name="TKey">键类型</typeparam>
|
||||||
|
/// <typeparam name="TValue">值类型</typeparam>
|
||||||
/// <param name="dict">字典</param>
|
/// <param name="dict">字典</param>
|
||||||
/// <param name="key">键</param>
|
/// <param name="key">键</param>
|
||||||
/// <param name="value">增加的值</param>
|
/// <param name="value">增加的值</param>
|
||||||
public static void Increase<TKey>(this Dictionary<TKey, int> dict, TKey key, int value)
|
public static void IncreaseValue<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key, TValue value)
|
||||||
where TKey : notnull
|
where TKey : notnull
|
||||||
|
where TValue : struct, IAdditionOperators<TValue, TValue, TValue>
|
||||||
{
|
{
|
||||||
// ref the value, so that we can manipulate it outside the dict.
|
// ref the value, so that we can manipulate it outside the dict.
|
||||||
ref int current = ref CollectionsMarshal.GetValueRefOrAddDefault(dict, key, out _);
|
ref TValue current = ref CollectionsMarshal.GetValueRefOrAddDefault(dict, key, out _);
|
||||||
current += value;
|
current += value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,13 +47,15 @@ internal static partial class EnumerableExtension
|
|||||||
/// 增加计数
|
/// 增加计数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="TKey">键类型</typeparam>
|
/// <typeparam name="TKey">键类型</typeparam>
|
||||||
|
/// <typeparam name="TValue">值类型</typeparam>
|
||||||
/// <param name="dict">字典</param>
|
/// <param name="dict">字典</param>
|
||||||
/// <param name="key">键</param>
|
/// <param name="key">键</param>
|
||||||
/// <returns>是否存在键值</returns>
|
/// <returns>是否存在键值</returns>
|
||||||
public static bool TryIncrease<TKey>(this Dictionary<TKey, int> dict, TKey key)
|
public static bool TryIncreaseOne<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key)
|
||||||
where TKey : notnull
|
where TKey : notnull
|
||||||
|
where TValue : struct, IIncrementOperators<TValue>
|
||||||
{
|
{
|
||||||
ref int value = ref CollectionsMarshal.GetValueRefOrNullRef(dict, key);
|
ref TValue value = ref CollectionsMarshal.GetValueRefOrNullRef(dict, key);
|
||||||
if (!Unsafe.IsNullRef(ref value))
|
if (!Unsafe.IsNullRef(ref value))
|
||||||
{
|
{
|
||||||
++value;
|
++value;
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ internal static class NumberExtension
|
|||||||
/// <param name="x">给定的整数</param>
|
/// <param name="x">给定的整数</param>
|
||||||
/// <returns>位数</returns>
|
/// <returns>位数</returns>
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static int Place(in this int x)
|
public static uint Place(in this uint x)
|
||||||
{
|
{
|
||||||
// Benchmarked and compared as a most optimized solution
|
// Benchmarked and compared as a most optimized solution
|
||||||
return (int)(MathF.Log10(x) + 1);
|
return (uint)(MathF.Log10(x) + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,82 +1,166 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"Name": "AchievementGoalId",
|
"Name": "AchievementGoalId",
|
||||||
"Type": "int",
|
"Documentation": "成就分类 Id",
|
||||||
"Documentation": "1-2位 成就分类Id"
|
"Equatable": true,
|
||||||
|
"EqualityOperators": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Name": "AchievementId",
|
"Name": "AchievementId",
|
||||||
"Type": "int",
|
"Documentation": "成就 Id",
|
||||||
"Documentation": "5位 成就Id"
|
"Equatable": true,
|
||||||
|
"EqualityOperators": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Name": "AvatarId",
|
"Name": "AvatarId",
|
||||||
"Type": "int",
|
"Documentation": "角色 Id",
|
||||||
"Documentation": "8位 角色Id"
|
"Equatable": true,
|
||||||
|
"EqualityOperators": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Name": "CostumeId",
|
"Name": "CostumeId",
|
||||||
"Type": "int",
|
"Documentation": "角色装扮 Id",
|
||||||
"Documentation": "6位 角色装扮Id"
|
"Equatable": true,
|
||||||
|
"EqualityOperators": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Name": "EquipAffixId",
|
"Name": "EquipAffixId",
|
||||||
"Type": "int",
|
"Documentation": "装备属性 Id",
|
||||||
"Documentation": "6位 装备属性Id"
|
"Equatable": true,
|
||||||
|
"EqualityOperators": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Name": "ExtendedEquipAffixId",
|
"Name": "ExtendedEquipAffixId",
|
||||||
"Type": "int",
|
"Documentation": "装备属性 Id",
|
||||||
"Documentation": "7位 装备属性Id"
|
"Equatable": true,
|
||||||
|
"EqualityOperators": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "FetterLevel",
|
||||||
|
"Documentation": "好感等级 1 - 10",
|
||||||
|
"Equatable": true,
|
||||||
|
"EqualityOperators": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "Level",
|
||||||
|
"Documentation": "等级 1 - 90",
|
||||||
|
"Equatable": true,
|
||||||
|
"EqualityOperators": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Name": "MaterialId",
|
"Name": "MaterialId",
|
||||||
"Type": "int",
|
"Documentation": "材料 Id",
|
||||||
"Documentation": "3-6位 材料Id"
|
"Equatable": true,
|
||||||
|
"EqualityOperators": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "MonsterDescribeId",
|
||||||
|
"Documentation": "怪物描述 Id",
|
||||||
|
"Equatable": true,
|
||||||
|
"EqualityOperators": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Name": "MonsterId",
|
"Name": "MonsterId",
|
||||||
"Type": "int",
|
"Documentation": "怪物 Id",
|
||||||
"Documentation": "8位 怪物Id"
|
"Equatable": true,
|
||||||
|
"EqualityOperators": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Name": "PromoteId",
|
"Name": "PromoteId",
|
||||||
"Type": "int",
|
"Documentation": "角色突破提升 Id",
|
||||||
"Documentation": "1-5位 角色突破提升Id"
|
"Equatable": true,
|
||||||
|
"EqualityOperators": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Name": "ReliquaryAffixId",
|
"Name": "PromoteLevel",
|
||||||
"Type": "int",
|
"Documentation": "突破等级 0 - 6",
|
||||||
"Documentation": "6位 圣遗物副词条Id"
|
"Equatable": true,
|
||||||
|
"EqualityOperators": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "ReliquaryLevel",
|
||||||
|
"Documentation": "圣遗物等级 1 - 21",
|
||||||
|
"Equatable": true,
|
||||||
|
"EqualityOperators": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "ReliquarySubAffixId",
|
||||||
|
"Documentation": "圣遗物副词条 Id",
|
||||||
|
"Equatable": true,
|
||||||
|
"EqualityOperators": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Name": "ReliquaryId",
|
"Name": "ReliquaryId",
|
||||||
"Type": "int",
|
"Documentation": "圣遗物 Id",
|
||||||
"Documentation": "5位 圣遗物Id"
|
"Equatable": true,
|
||||||
|
"EqualityOperators": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Name": "ReliquaryMainAffixId",
|
"Name": "ReliquaryMainAffixId",
|
||||||
"Type": "int",
|
"Documentation": "圣遗物主属性 Id",
|
||||||
"Documentation": "5位 圣遗物主属性Id"
|
"Equatable": true,
|
||||||
|
"EqualityOperators": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Name": "ReliquarySetId",
|
"Name": "ReliquarySetId",
|
||||||
"Type": "int",
|
"Documentation": "圣遗物套装 Id",
|
||||||
"Documentation": "5位 圣遗物套装Id"
|
"Equatable": true,
|
||||||
|
"EqualityOperators": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Name": "SkillGroupId",
|
"Name": "SkillGroupId",
|
||||||
"Type": "int",
|
"Documentation": "技能组 Id",
|
||||||
"Documentation": "3-4位 技能组Id"
|
"Equatable": true,
|
||||||
|
"EqualityOperators": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Name": "SkillId",
|
"Name": "SkillId",
|
||||||
"Type": "int",
|
"Documentation": "技能 Id",
|
||||||
"Documentation": "5-6位 技能Id"
|
"Equatable": true,
|
||||||
|
"EqualityOperators": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "SkillLevel",
|
||||||
|
"Documentation": "技能等级 1 - 15",
|
||||||
|
"Equatable": true,
|
||||||
|
"EqualityOperators": true,
|
||||||
|
"AdditionOperators": true,
|
||||||
|
"IncrementOperators": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "TowerLevelId",
|
||||||
|
"Documentation": "深渊间 Id",
|
||||||
|
"Equatable": true,
|
||||||
|
"EqualityOperators": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "TowerLevelGroupId",
|
||||||
|
"Documentation": "深渊间分组 Id",
|
||||||
|
"Equatable": true,
|
||||||
|
"EqualityOperators": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "TowerFloorId",
|
||||||
|
"Documentation": "深渊层 Id",
|
||||||
|
"Equatable": true,
|
||||||
|
"EqualityOperators": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "TowerScheduleId",
|
||||||
|
"Documentation": "深渊计划 Id",
|
||||||
|
"Equatable": true,
|
||||||
|
"EqualityOperators": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "WeaponAffixLevel",
|
||||||
|
"Documentation": "武器精炼等级 0 - 4",
|
||||||
|
"Equatable": true,
|
||||||
|
"EqualityOperators": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Name": "WeaponId",
|
"Name": "WeaponId",
|
||||||
"Type": "int",
|
"Documentation": "武器 Id",
|
||||||
"Documentation": "5位 武器Id"
|
"Equatable": true,
|
||||||
|
"EqualityOperators": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -42,7 +42,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasIndex("ArchiveId");
|
b.HasIndex("ArchiveId");
|
||||||
|
|
||||||
b.ToTable("achievements");
|
b.ToTable("achievements", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.AchievementArchive", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.AchievementArchive", b =>
|
||||||
@@ -60,7 +60,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasKey("InnerId");
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
b.ToTable("achievement_archives");
|
b.ToTable("achievement_archives", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.AvatarInfo", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.AvatarInfo", b =>
|
||||||
@@ -79,7 +79,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasKey("InnerId");
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
b.ToTable("avatar_infos");
|
b.ToTable("avatar_infos", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateEntry", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateEntry", b =>
|
||||||
@@ -101,7 +101,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasIndex("ProjectId");
|
b.HasIndex("ProjectId");
|
||||||
|
|
||||||
b.ToTable("cultivate_entries");
|
b.ToTable("cultivate_entries", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateItem", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateItem", b =>
|
||||||
@@ -126,7 +126,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasIndex("EntryId");
|
b.HasIndex("EntryId");
|
||||||
|
|
||||||
b.ToTable("cultivate_items");
|
b.ToTable("cultivate_items", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateProject", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateProject", b =>
|
||||||
@@ -147,7 +147,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasKey("InnerId");
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
b.ToTable("cultivate_projects");
|
b.ToTable("cultivate_projects", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.DailyNoteEntry", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.DailyNoteEntry", b =>
|
||||||
@@ -200,7 +200,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasIndex("UserId");
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
b.ToTable("daily_notes");
|
b.ToTable("daily_notes", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaArchive", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaArchive", b =>
|
||||||
@@ -218,7 +218,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasKey("InnerId");
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
b.ToTable("gacha_archives");
|
b.ToTable("gacha_archives", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaItem", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaItem", b =>
|
||||||
@@ -249,7 +249,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasIndex("ArchiveId");
|
b.HasIndex("ArchiveId");
|
||||||
|
|
||||||
b.ToTable("gacha_items");
|
b.ToTable("gacha_items", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.GameAccount", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.GameAccount", b =>
|
||||||
@@ -274,7 +274,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasKey("InnerId");
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
b.ToTable("game_accounts");
|
b.ToTable("game_accounts", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryItem", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryItem", b =>
|
||||||
@@ -296,7 +296,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasIndex("ProjectId");
|
b.HasIndex("ProjectId");
|
||||||
|
|
||||||
b.ToTable("inventory_items");
|
b.ToTable("inventory_items", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryReliquary", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryReliquary", b =>
|
||||||
@@ -325,7 +325,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasIndex("ProjectId");
|
b.HasIndex("ProjectId");
|
||||||
|
|
||||||
b.ToTable("inventory_reliquaries");
|
b.ToTable("inventory_reliquaries", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryWeapon", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryWeapon", b =>
|
||||||
@@ -350,7 +350,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasIndex("ProjectId");
|
b.HasIndex("ProjectId");
|
||||||
|
|
||||||
b.ToTable("inventory_weapons");
|
b.ToTable("inventory_weapons", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.ObjectCacheEntry", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.ObjectCacheEntry", b =>
|
||||||
@@ -366,7 +366,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasKey("Key");
|
b.HasKey("Key");
|
||||||
|
|
||||||
b.ToTable("object_cache");
|
b.ToTable("object_cache", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.SettingEntry", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.SettingEntry", b =>
|
||||||
@@ -379,7 +379,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasKey("Key");
|
b.HasKey("Key");
|
||||||
|
|
||||||
b.ToTable("settings");
|
b.ToTable("settings", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.SpiralAbyssEntry", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.SpiralAbyssEntry", b =>
|
||||||
@@ -401,7 +401,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasKey("InnerId");
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
b.ToTable("spiral_abysses");
|
b.ToTable("spiral_abysses", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.User", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.User", b =>
|
||||||
@@ -435,7 +435,7 @@ namespace Snap.Hutao.Migrations
|
|||||||
|
|
||||||
b.HasKey("InnerId");
|
b.HasKey("InnerId");
|
||||||
|
|
||||||
b.ToTable("users");
|
b.ToTable("users", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Snap.Hutao.Model.Entity.Achievement", b =>
|
modelBuilder.Entity("Snap.Hutao.Model.Entity.Achievement", b =>
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ namespace Snap.Hutao.Model.Calculable;
|
|||||||
[HighQuality]
|
[HighQuality]
|
||||||
internal sealed class CalculableAvatar : ObservableObject, ICalculableAvatar
|
internal sealed class CalculableAvatar : ObservableObject, ICalculableAvatar
|
||||||
{
|
{
|
||||||
private int levelCurrent;
|
private uint levelCurrent;
|
||||||
private int levelTarget;
|
private uint levelTarget;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构造一个新的可计算角色
|
/// 构造一个新的可计算角色
|
||||||
@@ -58,10 +58,10 @@ internal sealed class CalculableAvatar : ObservableObject, ICalculableAvatar
|
|||||||
public AvatarId AvatarId { get; }
|
public AvatarId AvatarId { get; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public int LevelMin { get; }
|
public uint LevelMin { get; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public int LevelMax { get; }
|
public uint LevelMax { get; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public List<ICalculableSkill> Skills { get; }
|
public List<ICalculableSkill> Skills { get; }
|
||||||
@@ -73,11 +73,11 @@ internal sealed class CalculableAvatar : ObservableObject, ICalculableAvatar
|
|||||||
public Uri Icon { get; }
|
public Uri Icon { get; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ItemQuality Quality { get; }
|
public QualityType Quality { get; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public int LevelCurrent { get => levelCurrent; set => SetProperty(ref levelCurrent, value); }
|
public uint LevelCurrent { get => levelCurrent; set => SetProperty(ref levelCurrent, value); }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public int LevelTarget { get => levelTarget; set => SetProperty(ref levelTarget, value); }
|
public uint LevelTarget { get => levelTarget; set => SetProperty(ref levelTarget, value); }
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,7 @@ using CommunityToolkit.Mvvm.ComponentModel;
|
|||||||
using Snap.Hutao.Model.Intrinsic;
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
using Snap.Hutao.Model.Metadata.Avatar;
|
using Snap.Hutao.Model.Metadata.Avatar;
|
||||||
using Snap.Hutao.Model.Metadata.Converter;
|
using Snap.Hutao.Model.Metadata.Converter;
|
||||||
|
using Snap.Hutao.Model.Primitive;
|
||||||
using Snap.Hutao.ViewModel.AvatarProperty;
|
using Snap.Hutao.ViewModel.AvatarProperty;
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.Calculable;
|
namespace Snap.Hutao.Model.Calculable;
|
||||||
@@ -15,8 +16,8 @@ namespace Snap.Hutao.Model.Calculable;
|
|||||||
[HighQuality]
|
[HighQuality]
|
||||||
internal sealed class CalculableSkill : ObservableObject, ICalculableSkill
|
internal sealed class CalculableSkill : ObservableObject, ICalculableSkill
|
||||||
{
|
{
|
||||||
private int levelCurrent;
|
private uint levelCurrent;
|
||||||
private int levelTarget;
|
private uint levelTarget;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构造一个新的可计算的技能
|
/// 构造一个新的可计算的技能
|
||||||
@@ -29,7 +30,7 @@ internal sealed class CalculableSkill : ObservableObject, ICalculableSkill
|
|||||||
LevelMax = 10; // hard coded 10 here
|
LevelMax = 10; // hard coded 10 here
|
||||||
Name = skill.Name;
|
Name = skill.Name;
|
||||||
Icon = SkillIconConverter.IconNameToUri(skill.Icon);
|
Icon = SkillIconConverter.IconNameToUri(skill.Icon);
|
||||||
Quality = ItemQuality.QUALITY_NONE;
|
Quality = QualityType.QUALITY_NONE;
|
||||||
|
|
||||||
LevelCurrent = LevelMin;
|
LevelCurrent = LevelMin;
|
||||||
LevelTarget = LevelMax;
|
LevelTarget = LevelMax;
|
||||||
@@ -46,20 +47,20 @@ internal sealed class CalculableSkill : ObservableObject, ICalculableSkill
|
|||||||
LevelMax = 10; // hard coded 10 here
|
LevelMax = 10; // hard coded 10 here
|
||||||
Name = skill.Name;
|
Name = skill.Name;
|
||||||
Icon = skill.Icon;
|
Icon = skill.Icon;
|
||||||
Quality = ItemQuality.QUALITY_NONE;
|
Quality = QualityType.QUALITY_NONE;
|
||||||
|
|
||||||
LevelCurrent = LevelMin;
|
LevelCurrent = LevelMin;
|
||||||
LevelTarget = LevelMax;
|
LevelTarget = LevelMax;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public int GruopId { get; }
|
public SkillGroupId GruopId { get; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public int LevelMin { get; }
|
public uint LevelMin { get; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public int LevelMax { get; }
|
public uint LevelMax { get; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
@@ -68,11 +69,11 @@ internal sealed class CalculableSkill : ObservableObject, ICalculableSkill
|
|||||||
public Uri Icon { get; }
|
public Uri Icon { get; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ItemQuality Quality { get; }
|
public QualityType Quality { get; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public int LevelCurrent { get => levelCurrent; set => SetProperty(ref levelCurrent, value); }
|
public uint LevelCurrent { get => levelCurrent; set => SetProperty(ref levelCurrent, value); }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public int LevelTarget { get => levelTarget; set => SetProperty(ref levelTarget, value); }
|
public uint LevelTarget { get => levelTarget; set => SetProperty(ref levelTarget, value); }
|
||||||
}
|
}
|
||||||
@@ -15,8 +15,8 @@ namespace Snap.Hutao.Model.Calculable;
|
|||||||
[HighQuality]
|
[HighQuality]
|
||||||
internal class CalculableWeapon : ObservableObject, ICalculableWeapon
|
internal class CalculableWeapon : ObservableObject, ICalculableWeapon
|
||||||
{
|
{
|
||||||
private int levelCurrent;
|
private uint levelCurrent;
|
||||||
private int levelTarget;
|
private uint levelTarget;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构造一个新的可计算武器
|
/// 构造一个新的可计算武器
|
||||||
@@ -56,10 +56,10 @@ internal class CalculableWeapon : ObservableObject, ICalculableWeapon
|
|||||||
public WeaponId WeaponId { get; }
|
public WeaponId WeaponId { get; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public int LevelMin { get; }
|
public uint LevelMin { get; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public int LevelMax { get; }
|
public uint LevelMax { get; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
@@ -68,11 +68,11 @@ internal class CalculableWeapon : ObservableObject, ICalculableWeapon
|
|||||||
public Uri Icon { get; }
|
public Uri Icon { get; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ItemQuality Quality { get; }
|
public QualityType Quality { get; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public int LevelCurrent { get => levelCurrent; set => SetProperty(ref levelCurrent, value); }
|
public uint LevelCurrent { get => levelCurrent; set => SetProperty(ref levelCurrent, value); }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public int LevelTarget { get => levelTarget; set => SetProperty(ref levelTarget, value); }
|
public uint LevelTarget { get => levelTarget; set => SetProperty(ref levelTarget, value); }
|
||||||
}
|
}
|
||||||
@@ -14,15 +14,15 @@ internal interface ICalculable : INameIcon
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 星级
|
/// 星级
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ItemQuality Quality { get; }
|
QualityType Quality { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 当前等级
|
/// 当前等级
|
||||||
/// </summary>
|
/// </summary>
|
||||||
int LevelCurrent { get; set; }
|
uint LevelCurrent { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 目标等级
|
/// 目标等级
|
||||||
/// </summary>
|
/// </summary>
|
||||||
int LevelTarget { get; set; }
|
uint LevelTarget { get; set; }
|
||||||
}
|
}
|
||||||
@@ -19,12 +19,12 @@ internal interface ICalculableAvatar : ICalculable
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 最小等级
|
/// 最小等级
|
||||||
/// </summary>
|
/// </summary>
|
||||||
int LevelMin { get; }
|
uint LevelMin { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 最大等级
|
/// 最大等级
|
||||||
/// </summary>
|
/// </summary>
|
||||||
int LevelMax { get; }
|
uint LevelMax { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 技能组
|
/// 技能组
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
// 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.Model.Primitive;
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.Calculable;
|
namespace Snap.Hutao.Model.Calculable;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -12,15 +14,15 @@ internal interface ICalculableSkill : ICalculable
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 技能组Id
|
/// 技能组Id
|
||||||
/// </summary>
|
/// </summary>
|
||||||
int GruopId { get; }
|
SkillGroupId GruopId { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 最小等级
|
/// 最小等级
|
||||||
/// </summary>
|
/// </summary>
|
||||||
int LevelMin { get; }
|
uint LevelMin { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 最大等级
|
/// 最大等级
|
||||||
/// </summary>
|
/// </summary>
|
||||||
int LevelMax { get; }
|
uint LevelMax { get; }
|
||||||
}
|
}
|
||||||
@@ -19,10 +19,10 @@ internal interface ICalculableWeapon : ICalculable
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 最小等级
|
/// 最小等级
|
||||||
/// </summary>
|
/// </summary>
|
||||||
int LevelMin { get; }
|
uint LevelMin { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 最大等级
|
/// 最大等级
|
||||||
/// </summary>
|
/// </summary>
|
||||||
int LevelMax { get; }
|
uint LevelMax { get; }
|
||||||
}
|
}
|
||||||
@@ -37,12 +37,12 @@ internal sealed class Achievement : IEquatable<Achievement>
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Id
|
/// Id
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Id { get; set; }
|
public uint Id { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 当前进度
|
/// 当前进度
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Current { get; set; }
|
public uint Current { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 完成时间
|
/// 完成时间
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ internal sealed class CultivateEntry
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 角色/武器/家具 Id
|
/// 角色/武器/家具 Id
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Id { get; set; }
|
public uint Id { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建一个新的养成入口点
|
/// 创建一个新的养成入口点
|
||||||
@@ -49,7 +49,7 @@ internal sealed class CultivateEntry
|
|||||||
/// <param name="type">类型</param>
|
/// <param name="type">类型</param>
|
||||||
/// <param name="id">主Id</param>
|
/// <param name="id">主Id</param>
|
||||||
/// <returns>养成入口点</returns>
|
/// <returns>养成入口点</returns>
|
||||||
public static CultivateEntry Create(in Guid projectId, CultivateType type, int id)
|
public static CultivateEntry Create(in Guid projectId, CultivateType type, uint id)
|
||||||
{
|
{
|
||||||
return new()
|
return new()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ internal sealed class GachaItem
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 物品Id
|
/// 物品Id
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int ItemId { get; set; }
|
public uint ItemId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取时间
|
/// 获取时间
|
||||||
@@ -66,12 +66,12 @@ internal sealed class GachaItem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="itemId">物品Id</param>
|
/// <param name="itemId">物品Id</param>
|
||||||
/// <returns>物品类型字符串</returns>
|
/// <returns>物品类型字符串</returns>
|
||||||
public static string GetItemTypeStringByItemId(int itemId)
|
public static string GetItemTypeStringByItemId(uint itemId)
|
||||||
{
|
{
|
||||||
return itemId.Place() switch
|
return itemId.Place() switch
|
||||||
{
|
{
|
||||||
8 => "角色",
|
8U => "角色",
|
||||||
5 => "武器",
|
5U => "武器",
|
||||||
_ => "未知",
|
_ => "未知",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -83,7 +83,7 @@ internal sealed class GachaItem
|
|||||||
/// <param name="item">祈愿物品</param>
|
/// <param name="item">祈愿物品</param>
|
||||||
/// <param name="itemId">物品Id</param>
|
/// <param name="itemId">物品Id</param>
|
||||||
/// <returns>新的祈愿物品</returns>
|
/// <returns>新的祈愿物品</returns>
|
||||||
public static GachaItem Create(in Guid archiveId, GachaLogItem item, int itemId)
|
public static GachaItem Create(in Guid archiveId, GachaLogItem item, uint itemId)
|
||||||
{
|
{
|
||||||
return new()
|
return new()
|
||||||
{
|
{
|
||||||
@@ -103,7 +103,7 @@ internal sealed class GachaItem
|
|||||||
/// <param name="item">祈愿物品</param>
|
/// <param name="item">祈愿物品</param>
|
||||||
/// <param name="itemId">物品Id</param>
|
/// <param name="itemId">物品Id</param>
|
||||||
/// <returns>新的祈愿物品</returns>
|
/// <returns>新的祈愿物品</returns>
|
||||||
public static GachaItem CreateForMajor2Minor2OrLower(in Guid archiveId, UIGFItem item, int itemId)
|
public static GachaItem CreateForMajor2Minor2OrLower(in Guid archiveId, UIGFItem item, uint itemId)
|
||||||
{
|
{
|
||||||
return new()
|
return new()
|
||||||
{
|
{
|
||||||
@@ -129,7 +129,7 @@ internal sealed class GachaItem
|
|||||||
ArchiveId = archiveId,
|
ArchiveId = archiveId,
|
||||||
GachaType = item.GachaType,
|
GachaType = item.GachaType,
|
||||||
QueryType = item.UIGFGachaType,
|
QueryType = item.UIGFGachaType,
|
||||||
ItemId = int.Parse(item.ItemId),
|
ItemId = uint.Parse(item.ItemId),
|
||||||
Time = item.Time,
|
Time = item.Time,
|
||||||
Id = item.Id,
|
Id = item.Id,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ internal sealed class InventoryItem
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 物品Id
|
/// 物品Id
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int ItemId { get; set; }
|
public uint ItemId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 个数 4294967295
|
/// 个数 4294967295
|
||||||
@@ -47,7 +47,7 @@ internal sealed class InventoryItem
|
|||||||
/// <param name="projectId">项目Id</param>
|
/// <param name="projectId">项目Id</param>
|
||||||
/// <param name="itemId">物品Id</param>
|
/// <param name="itemId">物品Id</param>
|
||||||
/// <returns>新的个数为0的物品</returns>
|
/// <returns>新的个数为0的物品</returns>
|
||||||
public static InventoryItem Create(in Guid projectId, int itemId)
|
public static InventoryItem Create(in Guid projectId, uint itemId)
|
||||||
{
|
{
|
||||||
return new()
|
return new()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ internal sealed class UIAFItem
|
|||||||
/// 成就Id
|
/// 成就Id
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonPropertyName("id")]
|
[JsonPropertyName("id")]
|
||||||
public int Id { get; set; }
|
public uint Id { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 完成时间
|
/// 完成时间
|
||||||
@@ -27,7 +27,7 @@ internal sealed class UIAFItem
|
|||||||
/// 对于progress为1的项,该属性始终为0
|
/// 对于progress为1的项,该属性始终为0
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonPropertyName("current")]
|
[JsonPropertyName("current")]
|
||||||
public int Current { get; set; }
|
public uint Current { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 完成状态
|
/// 完成状态
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ internal sealed class UIGFInfo
|
|||||||
/// 导出的时间戳
|
/// 导出的时间戳
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonPropertyName("export_timestamp")]
|
[JsonPropertyName("export_timestamp")]
|
||||||
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)]
|
|
||||||
public long? ExportTimestamp { get; set; }
|
public long? ExportTimestamp { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ internal sealed class UIIFInfo
|
|||||||
/// 导出的时间戳
|
/// 导出的时间戳
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonPropertyName("export_timestamp")]
|
[JsonPropertyName("export_timestamp")]
|
||||||
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)]
|
|
||||||
public long? ExportTimestamp { get; set; }
|
public long? ExportTimestamp { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -36,37 +36,45 @@ internal enum GrowCurveType
|
|||||||
GROW_CURVE_HP_2 = 23,
|
GROW_CURVE_HP_2 = 23,
|
||||||
GROW_CURVE_ATTACK_2 = 24,
|
GROW_CURVE_ATTACK_2 = 24,
|
||||||
GROW_CURVE_HP_ENVIRONMENT = 25,
|
GROW_CURVE_HP_ENVIRONMENT = 25,
|
||||||
|
|
||||||
GROW_CURVE_ATTACK_S5 = 31,
|
GROW_CURVE_ATTACK_S5 = 31,
|
||||||
GROW_CURVE_ATTACK_S4 = 32,
|
GROW_CURVE_ATTACK_S4 = 32,
|
||||||
GROW_CURVE_ATTACK_S3 = 33,
|
GROW_CURVE_ATTACK_S3 = 33,
|
||||||
GROW_CURVE_STRIKE_S5 = 34,
|
GROW_CURVE_STRIKE_S5 = 34,
|
||||||
|
|
||||||
GROW_CURVE_DEFENSE_S5 = 41,
|
GROW_CURVE_DEFENSE_S5 = 41,
|
||||||
GROW_CURVE_DEFENSE_S4 = 42,
|
GROW_CURVE_DEFENSE_S4 = 42,
|
||||||
|
|
||||||
GROW_CURVE_ATTACK_101 = 1101,
|
GROW_CURVE_ATTACK_101 = 1101,
|
||||||
GROW_CURVE_ATTACK_102 = 1102,
|
GROW_CURVE_ATTACK_102 = 1102,
|
||||||
GROW_CURVE_ATTACK_103 = 1103,
|
GROW_CURVE_ATTACK_103 = 1103,
|
||||||
GROW_CURVE_ATTACK_104 = 1104,
|
GROW_CURVE_ATTACK_104 = 1104,
|
||||||
GROW_CURVE_ATTACK_105 = 1105,
|
GROW_CURVE_ATTACK_105 = 1105,
|
||||||
|
|
||||||
GROW_CURVE_ATTACK_201 = 1201,
|
GROW_CURVE_ATTACK_201 = 1201,
|
||||||
GROW_CURVE_ATTACK_202 = 1202,
|
GROW_CURVE_ATTACK_202 = 1202,
|
||||||
GROW_CURVE_ATTACK_203 = 1203,
|
GROW_CURVE_ATTACK_203 = 1203,
|
||||||
GROW_CURVE_ATTACK_204 = 1204,
|
GROW_CURVE_ATTACK_204 = 1204,
|
||||||
GROW_CURVE_ATTACK_205 = 1205,
|
GROW_CURVE_ATTACK_205 = 1205,
|
||||||
|
|
||||||
GROW_CURVE_ATTACK_301 = 1301,
|
GROW_CURVE_ATTACK_301 = 1301,
|
||||||
GROW_CURVE_ATTACK_302 = 1302,
|
GROW_CURVE_ATTACK_302 = 1302,
|
||||||
GROW_CURVE_ATTACK_303 = 1303,
|
GROW_CURVE_ATTACK_303 = 1303,
|
||||||
GROW_CURVE_ATTACK_304 = 1304,
|
GROW_CURVE_ATTACK_304 = 1304,
|
||||||
GROW_CURVE_ATTACK_305 = 1305,
|
GROW_CURVE_ATTACK_305 = 1305,
|
||||||
|
|
||||||
GROW_CURVE_CRITICAL_101 = 2101,
|
GROW_CURVE_CRITICAL_101 = 2101,
|
||||||
GROW_CURVE_CRITICAL_102 = 2102,
|
GROW_CURVE_CRITICAL_102 = 2102,
|
||||||
GROW_CURVE_CRITICAL_103 = 2103,
|
GROW_CURVE_CRITICAL_103 = 2103,
|
||||||
GROW_CURVE_CRITICAL_104 = 2104,
|
GROW_CURVE_CRITICAL_104 = 2104,
|
||||||
GROW_CURVE_CRITICAL_105 = 2105,
|
GROW_CURVE_CRITICAL_105 = 2105,
|
||||||
|
|
||||||
GROW_CURVE_CRITICAL_201 = 2201,
|
GROW_CURVE_CRITICAL_201 = 2201,
|
||||||
GROW_CURVE_CRITICAL_202 = 2202,
|
GROW_CURVE_CRITICAL_202 = 2202,
|
||||||
GROW_CURVE_CRITICAL_203 = 2203,
|
GROW_CURVE_CRITICAL_203 = 2203,
|
||||||
GROW_CURVE_CRITICAL_204 = 2204,
|
GROW_CURVE_CRITICAL_204 = 2204,
|
||||||
GROW_CURVE_CRITICAL_205 = 2205,
|
GROW_CURVE_CRITICAL_205 = 2205,
|
||||||
|
|
||||||
GROW_CURVE_CRITICAL_301 = 2301,
|
GROW_CURVE_CRITICAL_301 = 2301,
|
||||||
GROW_CURVE_CRITICAL_302 = 2302,
|
GROW_CURVE_CRITICAL_302 = 2302,
|
||||||
GROW_CURVE_CRITICAL_303 = 2303,
|
GROW_CURVE_CRITICAL_303 = 2303,
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ internal static class IntrinsicImmutables
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 物品类型
|
/// 物品类型
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly ImmutableHashSet<string> ItemQualities = Enum.GetValues<ItemQuality>().Select(e => e.GetLocalizedDescriptionOrDefault()).OfType<string>().ToImmutableHashSet();
|
public static readonly ImmutableHashSet<string> ItemQualities = Enum.GetValues<QualityType>().Select(e => e.GetLocalizedDescriptionOrDefault()).OfType<string>().ToImmutableHashSet();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 身材类型
|
/// 身材类型
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ internal enum MaterialType
|
|||||||
MATERIAL_NONE = 0,
|
MATERIAL_NONE = 0,
|
||||||
MATERIAL_FOOD = 1,
|
MATERIAL_FOOD = 1,
|
||||||
MATERIAL_QUEST = 2,
|
MATERIAL_QUEST = 2,
|
||||||
|
|
||||||
MATERIAL_EXCHANGE = 4,
|
MATERIAL_EXCHANGE = 4,
|
||||||
MATERIAL_CONSUME = 5,
|
MATERIAL_CONSUME = 5,
|
||||||
MATERIAL_EXP_FRUIT = 6,
|
MATERIAL_EXP_FRUIT = 6,
|
||||||
@@ -34,6 +35,7 @@ internal enum MaterialType
|
|||||||
MATERIAL_FAKE_ABSORBATE = 23,
|
MATERIAL_FAKE_ABSORBATE = 23,
|
||||||
MATERIAL_CONSUME_BATCH_USE = 24,
|
MATERIAL_CONSUME_BATCH_USE = 24,
|
||||||
MATERIAL_WOOD = 25,
|
MATERIAL_WOOD = 25,
|
||||||
|
|
||||||
MATERIAL_FURNITURE_FORMULA = 27,
|
MATERIAL_FURNITURE_FORMULA = 27,
|
||||||
MATERIAL_CHANNELLER_SLAB_BUFF = 28,
|
MATERIAL_CHANNELLER_SLAB_BUFF = 28,
|
||||||
MATERIAL_FURNITURE_SUITE_FORMULA = 29,
|
MATERIAL_FURNITURE_SUITE_FORMULA = 29,
|
||||||
@@ -41,7 +43,7 @@ internal enum MaterialType
|
|||||||
MATERIAL_HOME_SEED = 31,
|
MATERIAL_HOME_SEED = 31,
|
||||||
MATERIAL_FISH_BAIT = 32,
|
MATERIAL_FISH_BAIT = 32,
|
||||||
MATERIAL_FISH_ROD = 33,
|
MATERIAL_FISH_ROD = 33,
|
||||||
MATERIAL_SUMO_BUFF = 34, // never appear
|
MATERIAL_SUMO_BUFF = 34, // sumo 活动道具,never appear
|
||||||
MATERIAL_FIREWORKS = 35,
|
MATERIAL_FIREWORKS = 35,
|
||||||
MATERIAL_BGM = 36,
|
MATERIAL_BGM = 36,
|
||||||
MATERIAL_SPICE_FOOD = 37,
|
MATERIAL_SPICE_FOOD = 37,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace Snap.Hutao.Model.Intrinsic;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[HighQuality]
|
[HighQuality]
|
||||||
[Localization]
|
[Localization]
|
||||||
internal enum ItemQuality
|
internal enum QualityType
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 无
|
/// 无
|
||||||
@@ -29,5 +29,5 @@ internal class Item : INameIcon
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 星级
|
/// 星级
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ItemQuality Quality { get; set; }
|
public QualityType Quality { get; set; }
|
||||||
}
|
}
|
||||||
@@ -19,5 +19,5 @@ internal interface INameQuality
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 星级
|
/// 星级
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ItemQuality Quality { get; }
|
QualityType Quality { get; }
|
||||||
}
|
}
|
||||||
@@ -15,7 +15,7 @@ internal interface ISummaryItemSource
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 星级
|
/// 星级
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ItemQuality Quality { get; }
|
QualityType Quality { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 转换到简述统计物品
|
/// 转换到简述统计物品
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ internal sealed class Achievement
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 排序顺序
|
/// 排序顺序
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Order { get; set; }
|
public uint Order { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 标题
|
/// 标题
|
||||||
@@ -44,7 +44,7 @@ internal sealed class Achievement
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 总进度
|
/// 总进度
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Progress { get; set; }
|
public uint Progress { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 图标
|
/// 图标
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ internal sealed class AchievementGoal
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 排序顺序
|
/// 排序顺序
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Order { get; set; }
|
public uint Order { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 名称
|
/// 名称
|
||||||
|
|||||||
@@ -18,5 +18,5 @@ internal sealed class Reward
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 数量
|
/// 数量
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Count { get; set; }
|
public uint Count { get; set; }
|
||||||
}
|
}
|
||||||
@@ -18,6 +18,7 @@ internal partial class Avatar : IStatisticsItemSource, ISummaryItemSource, IName
|
|||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// [非元数据] 搭配数据
|
/// [非元数据] 搭配数据
|
||||||
|
/// TODO:Add View suffix.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public AvatarCollocationView? Collocation { get; set; }
|
public AvatarCollocationView? Collocation { get; set; }
|
||||||
@@ -37,7 +38,7 @@ internal partial class Avatar : IStatisticsItemSource, ISummaryItemSource, IName
|
|||||||
/// 最大等级
|
/// 最大等级
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SuppressMessage("", "CA1822")]
|
[SuppressMessage("", "CA1822")]
|
||||||
public int MaxLevel { get => 90; }
|
public uint MaxLevel { get => 90U; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ICalculableAvatar ToCalculable()
|
public ICalculableAvatar ToCalculable()
|
||||||
|
|||||||
@@ -26,12 +26,11 @@ internal partial class Avatar
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 排序号
|
/// 排序号
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Sort { get; set; }
|
public uint Sort { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 体型
|
/// 体型
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonEnum(JsonSerializeType.String)]
|
|
||||||
public BodyType Body { get; set; } = default!;
|
public BodyType Body { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -62,7 +61,7 @@ internal partial class Avatar
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 星级
|
/// 星级
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ItemQuality Quality { get; set; }
|
public QualityType Quality { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 武器类型
|
/// 武器类型
|
||||||
@@ -72,12 +71,12 @@ internal partial class Avatar
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 基础数值
|
/// 基础数值
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public BaseValue BaseValue { get; set; } = default!;
|
public AvatarBaseValue BaseValue { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 生长曲线
|
/// 生长曲线
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Dictionary<FightProperty, GrowCurveType> GrowCurves { get; set; } = default!;
|
public List<TypeValue<FightProperty, GrowCurveType>> GrowCurves { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 技能
|
/// 技能
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Core.Json.Annotation;
|
||||||
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
|
using Snap.Hutao.Model.Primitive;
|
||||||
|
using Snap.Hutao.ViewModel.Wiki;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Model.Metadata.Avatar;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 角色基础数值
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class AvatarBaseValue : BaseValue
|
||||||
|
{
|
||||||
|
public PropertyCurveValue GetPropertyCurveValue(FightProperty fightProperty)
|
||||||
|
{
|
||||||
|
// TODO: impl
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,7 +34,7 @@ internal sealed class Costume
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 图标
|
/// 图标
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Icon { get; set; } = default!;
|
public string FrontIcon { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 侧面图标
|
/// 侧面图标
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ internal sealed class FetterInfo
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 地区
|
/// 地区
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonEnum(JsonSerializeType.String)]
|
|
||||||
public AssociationType Association { get; set; } = default!;
|
public AssociationType Association { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -36,12 +35,12 @@ internal sealed class FetterInfo
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 生月
|
/// 生月
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int BirthMonth { get; set; }
|
public uint BirthMonth { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 生日
|
/// 生日
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int BirthDay { get; set; }
|
public uint BirthDay { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 格式化的生日日期
|
/// 格式化的生日日期
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ namespace Snap.Hutao.Model.Metadata;
|
|||||||
[SuppressMessage("", "SA1600")]
|
[SuppressMessage("", "SA1600")]
|
||||||
internal static class AvatarIds
|
internal static class AvatarIds
|
||||||
{
|
{
|
||||||
|
// 此处的变量名称以 UI_AvatarIcon 为准
|
||||||
public static readonly AvatarId Ayaka = 10000002;
|
public static readonly AvatarId Ayaka = 10000002;
|
||||||
public static readonly AvatarId Qin = 10000003;
|
public static readonly AvatarId Qin = 10000003;
|
||||||
|
|
||||||
@@ -106,7 +107,7 @@ internal static class AvatarIds
|
|||||||
Name = "旅行者",
|
Name = "旅行者",
|
||||||
Icon = "UI_AvatarIcon_PlayerBoy",
|
Icon = "UI_AvatarIcon_PlayerBoy",
|
||||||
SideIcon = "UI_AvatarIcon_Side_PlayerBoy",
|
SideIcon = "UI_AvatarIcon_Side_PlayerBoy",
|
||||||
Quality = Intrinsic.ItemQuality.QUALITY_ORANGE,
|
Quality = Intrinsic.QualityType.QUALITY_ORANGE,
|
||||||
},
|
},
|
||||||
|
|
||||||
[PlayerGirl] = new()
|
[PlayerGirl] = new()
|
||||||
@@ -114,7 +115,7 @@ internal static class AvatarIds
|
|||||||
Name = "旅行者",
|
Name = "旅行者",
|
||||||
Icon = "UI_AvatarIcon_PlayerGirl",
|
Icon = "UI_AvatarIcon_PlayerGirl",
|
||||||
SideIcon = "UI_AvatarIcon_Side_PlayerGirl",
|
SideIcon = "UI_AvatarIcon_Side_PlayerGirl",
|
||||||
Quality = Intrinsic.ItemQuality.QUALITY_ORANGE,
|
Quality = Intrinsic.QualityType.QUALITY_ORANGE,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ internal class BaseValue
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="fightProperty">战斗属性</param>
|
/// <param name="fightProperty">战斗属性</param>
|
||||||
/// <returns>值</returns>
|
/// <returns>值</returns>
|
||||||
public float GetValue(FightProperty fightProperty)
|
public virtual float GetValue(FightProperty fightProperty)
|
||||||
{
|
{
|
||||||
return fightProperty switch
|
return fightProperty switch
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ internal sealed partial class DescriptionsParametersDescriptor : ValueConverter<
|
|||||||
/// <param name="from">源</param>
|
/// <param name="from">源</param>
|
||||||
/// <param name="level">等级</param>
|
/// <param name="level">等级</param>
|
||||||
/// <returns>特定等级的解释</returns>
|
/// <returns>特定等级的解释</returns>
|
||||||
public static LevelParameters<string, ParameterDescription> Convert(DescriptionsParameters from, int level)
|
public static LevelParameters<string, ParameterDescription> Convert(DescriptionsParameters from, uint level)
|
||||||
{
|
{
|
||||||
LevelParameters<int, float> param = from.Parameters.Single(param => param.Level == level);
|
LevelParameters<int, float> param = from.Parameters.Single(param => param.Level == level);
|
||||||
return new LevelParameters<string, ParameterDescription>($"Lv.{param.Level}", GetParameterDescription(from.Descriptions, param.Parameters));
|
return new LevelParameters<string, ParameterDescription>($"Lv.{param.Level}", GetParameterDescription(from.Descriptions, param.Parameters));
|
||||||
|
|||||||
@@ -13,18 +13,18 @@ namespace Snap.Hutao.Model.Metadata.Converter;
|
|||||||
/// 品质颜色转换器
|
/// 品质颜色转换器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HighQuality]
|
[HighQuality]
|
||||||
internal sealed class QualityColorConverter : ValueConverter<ItemQuality, Color>
|
internal sealed class QualityColorConverter : ValueConverter<QualityType, Color>
|
||||||
{
|
{
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override Color Convert(ItemQuality from)
|
public override Color Convert(QualityType from)
|
||||||
{
|
{
|
||||||
return from switch
|
return from switch
|
||||||
{
|
{
|
||||||
ItemQuality.QUALITY_WHITE => StructMarshal.Color(0xFF72778B),
|
QualityType.QUALITY_WHITE => StructMarshal.Color(0xFF72778B),
|
||||||
ItemQuality.QUALITY_GREEN => StructMarshal.Color(0xFF2A8F72),
|
QualityType.QUALITY_GREEN => StructMarshal.Color(0xFF2A8F72),
|
||||||
ItemQuality.QUALITY_BLUE => StructMarshal.Color(0xFF5180CB),
|
QualityType.QUALITY_BLUE => StructMarshal.Color(0xFF5180CB),
|
||||||
ItemQuality.QUALITY_PURPLE => StructMarshal.Color(0xFFA156E0),
|
QualityType.QUALITY_PURPLE => StructMarshal.Color(0xFFA156E0),
|
||||||
ItemQuality.QUALITY_ORANGE or ItemQuality.QUALITY_ORANGE_SP => StructMarshal.Color(0xFFBC6932),
|
QualityType.QUALITY_ORANGE or QualityType.QUALITY_ORANGE_SP => StructMarshal.Color(0xFFBC6932),
|
||||||
_ => Colors.Transparent,
|
_ => Colors.Transparent,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,13 +10,13 @@ namespace Snap.Hutao.Model.Metadata.Converter;
|
|||||||
/// 物品等级转换器
|
/// 物品等级转换器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HighQuality]
|
[HighQuality]
|
||||||
internal sealed class QualityConverter : ValueConverter<ItemQuality, Uri>
|
internal sealed class QualityConverter : ValueConverter<QualityType, Uri>
|
||||||
{
|
{
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override Uri Convert(ItemQuality from)
|
public override Uri Convert(QualityType from)
|
||||||
{
|
{
|
||||||
string name = Enum.GetName(from) ?? from.ToString();
|
string name = Enum.GetName(from) ?? from.ToString();
|
||||||
if (name == nameof(ItemQuality.QUALITY_ORANGE_SP))
|
if (name == nameof(QualityType.QUALITY_ORANGE_SP))
|
||||||
{
|
{
|
||||||
name = "QUALITY_RED";
|
name = "QUALITY_RED";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,11 +21,21 @@ internal sealed class GachaEvent
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string Version { get; set; } = default!;
|
public string Version { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 顺序
|
||||||
|
/// </summary>
|
||||||
|
public uint Order { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 卡池图
|
/// 卡池图
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Uri Banner { get; set; } = default!;
|
public Uri Banner { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 卡池图2
|
||||||
|
/// </summary>
|
||||||
|
public Uri Banner2 { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 开始时间
|
/// 开始时间
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -44,10 +54,10 @@ internal sealed class GachaEvent
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 五星列表
|
/// 五星列表
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<int> UpOrangeList { get; set; } = default!;
|
public List<uint> UpOrangeList { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 四星列表
|
/// 四星列表
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<int> UpPurpleList { get; set; } = default!;
|
public List<uint> UpPurpleList { get; set; } = default!;
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Snap.Hutao.Model.Intrinsic;
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
|
using Snap.Hutao.Model.Primitive;
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.Metadata;
|
namespace Snap.Hutao.Model.Metadata;
|
||||||
|
|
||||||
@@ -11,13 +12,23 @@ namespace Snap.Hutao.Model.Metadata;
|
|||||||
[HighQuality]
|
[HighQuality]
|
||||||
internal sealed class GrowCurve
|
internal sealed class GrowCurve
|
||||||
{
|
{
|
||||||
|
private Dictionary<GrowCurveType, float>? curveMap;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 等级
|
/// 等级
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Level { get; set; }
|
public Level Level { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 曲线 值相乘
|
/// 曲线 值相乘
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Dictionary<GrowCurveType, float> Curves { get; set; } = default!;
|
public List<TypeValue<GrowCurveType, float>> Curves { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 曲线映射
|
||||||
|
/// </summary>
|
||||||
|
public Dictionary<GrowCurveType, float> CurveMap
|
||||||
|
{
|
||||||
|
get => curveMap ??= Curves.ToDictionary(v => v.Type, v => v.Value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,7 @@ namespace Snap.Hutao.Model.Metadata.Item;
|
|||||||
/// 展示物品
|
/// 展示物品
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HighQuality]
|
[HighQuality]
|
||||||
internal class Display
|
internal class DisplayItem
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 物品Id
|
/// 物品Id
|
||||||
@@ -20,7 +20,7 @@ internal class Display
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 等级
|
/// 等级
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ItemQuality RankLevel { get; set; }
|
public QualityType RankLevel { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 物品类型
|
/// 物品类型
|
||||||
@@ -11,44 +11,8 @@ namespace Snap.Hutao.Model.Metadata.Item;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 材料
|
/// 材料
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal sealed class Material : Display
|
internal sealed class Material : DisplayItem
|
||||||
{
|
{
|
||||||
private static readonly ImmutableHashSet<MaterialId> MondayThursdayItems = new HashSet<MaterialId>
|
|
||||||
{
|
|
||||||
104301, 104302, 104303, // 「自由」
|
|
||||||
104310, 104311, 104312, // 「繁荣」
|
|
||||||
104320, 104321, 104322, // 「浮世」
|
|
||||||
104329, 104330, 104331, // 「诤言」
|
|
||||||
114001, 114002, 114003, 114004, // 高塔孤王
|
|
||||||
114013, 114014, 114015, 114016, // 孤云寒林
|
|
||||||
114025, 114026, 114027, 114028, // 远海夷地
|
|
||||||
114037, 114038, 114039, 114040, // 谧林涓露
|
|
||||||
}.ToImmutableHashSet();
|
|
||||||
|
|
||||||
private static readonly ImmutableHashSet<MaterialId> TuesdayFridayItems = new HashSet<MaterialId>
|
|
||||||
{
|
|
||||||
104304, 104305, 104306, // 「抗争」
|
|
||||||
104313, 104314, 104315, // 「勤劳」
|
|
||||||
104323, 104324, 104325, // 「风雅」
|
|
||||||
104332, 104333, 104334, // 「巧思」
|
|
||||||
114005, 114006, 114007, 114008, // 凛风奔狼
|
|
||||||
114017, 114018, 114019, 114020, // 雾海云间
|
|
||||||
114029, 114030, 114031, 114032, // 鸣神御灵
|
|
||||||
114041, 114042, 114043, 114044, // 绿洲花园
|
|
||||||
}.ToImmutableHashSet();
|
|
||||||
|
|
||||||
private static readonly ImmutableHashSet<MaterialId> WednesdaySaturdayItems = new HashSet<MaterialId>
|
|
||||||
{
|
|
||||||
104307, 104308, 104309, // 「诗文」
|
|
||||||
104316, 104317, 104318, // 「黄金」
|
|
||||||
104326, 104327, 104328, // 「天光」
|
|
||||||
104335, 104336, 104337, // 「笃行」
|
|
||||||
114009, 114010, 114011, 114012, // 狮牙斗士
|
|
||||||
114021, 114022, 114023, 114024, // 漆黑陨铁
|
|
||||||
114033, 114034, 114035, 114036, // 今昔剧画
|
|
||||||
114045, 114046, 114047, 114048, // 谧林涓露
|
|
||||||
}.ToImmutableHashSet();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 材料类型
|
/// 材料类型
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -66,23 +30,24 @@ internal sealed class Material : Display
|
|||||||
public bool IsInventoryItem()
|
public bool IsInventoryItem()
|
||||||
{
|
{
|
||||||
// 原质
|
// 原质
|
||||||
if (Id == 112001)
|
if (Id == 112001U)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 摩拉
|
// 摩拉
|
||||||
if (Id == 202)
|
if (Id == 202U)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: support non-CHS
|
||||||
if (TypeDescription.EndsWith("区域特产"))
|
if (TypeDescription.EndsWith("区域特产"))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Currently only support CN
|
// TODO: support non-CHS
|
||||||
return TypeDescription switch
|
return TypeDescription switch
|
||||||
{
|
{
|
||||||
"角色与武器培养素材" => true, // 怪物掉落
|
"角色与武器培养素材" => true, // 怪物掉落
|
||||||
@@ -106,9 +71,9 @@ internal sealed class Material : Display
|
|||||||
{
|
{
|
||||||
return DateTimeOffset.UtcNow.AddHours(4).DayOfWeek switch
|
return DateTimeOffset.UtcNow.AddHours(4).DayOfWeek switch
|
||||||
{
|
{
|
||||||
DayOfWeek.Monday or DayOfWeek.Thursday => MondayThursdayItems.Contains(Id),
|
DayOfWeek.Monday or DayOfWeek.Thursday => Materials.MondayThursdayItems.Contains(Id),
|
||||||
DayOfWeek.Tuesday or DayOfWeek.Friday => TuesdayFridayItems.Contains(Id),
|
DayOfWeek.Tuesday or DayOfWeek.Friday => Materials.TuesdayFridayItems.Contains(Id),
|
||||||
DayOfWeek.Wednesday or DayOfWeek.Saturday => WednesdaySaturdayItems.Contains(Id),
|
DayOfWeek.Wednesday or DayOfWeek.Saturday => Materials.WednesdaySaturdayItems.Contains(Id),
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -119,17 +84,17 @@ internal sealed class Material : Display
|
|||||||
/// <returns>DaysOfWeek</returns>
|
/// <returns>DaysOfWeek</returns>
|
||||||
public DaysOfWeek GetDaysOfWeek()
|
public DaysOfWeek GetDaysOfWeek()
|
||||||
{
|
{
|
||||||
if (MondayThursdayItems.Contains(Id))
|
if (Materials.MondayThursdayItems.Contains(Id))
|
||||||
{
|
{
|
||||||
return DaysOfWeek.MondayAndThursday;
|
return DaysOfWeek.MondayAndThursday;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TuesdayFridayItems.Contains(Id))
|
if (Materials.TuesdayFridayItems.Contains(Id))
|
||||||
{
|
{
|
||||||
return DaysOfWeek.TuesdayAndFriday;
|
return DaysOfWeek.TuesdayAndFriday;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WednesdaySaturdayItems.Contains(Id))
|
if (Materials.WednesdaySaturdayItems.Contains(Id))
|
||||||
{
|
{
|
||||||
return DaysOfWeek.WednesdayAndSaturday;
|
return DaysOfWeek.WednesdayAndSaturday;
|
||||||
}
|
}
|
||||||
|
|||||||
66
src/Snap.Hutao/Snap.Hutao/Model/Metadata/Item/Materials.cs
Normal file
66
src/Snap.Hutao/Snap.Hutao/Model/Metadata/Item/Materials.cs
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
|
using Snap.Hutao.Model.Primitive;
|
||||||
|
using Snap.Hutao.ViewModel.Cultivation;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Model.Metadata.Item;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 材料表
|
||||||
|
/// </summary>
|
||||||
|
internal static class Materials
|
||||||
|
{
|
||||||
|
private static readonly ImmutableHashSet<MaterialId> MondayThursdayItemsInner = new HashSet<MaterialId>
|
||||||
|
{
|
||||||
|
104301, 104302, 104303, // 「自由」
|
||||||
|
104310, 104311, 104312, // 「繁荣」
|
||||||
|
104320, 104321, 104322, // 「浮世」
|
||||||
|
104329, 104330, 104331, // 「诤言」
|
||||||
|
114001, 114002, 114003, 114004, // 高塔孤王
|
||||||
|
114013, 114014, 114015, 114016, // 孤云寒林
|
||||||
|
114025, 114026, 114027, 114028, // 远海夷地
|
||||||
|
114037, 114038, 114039, 114040, // 谧林涓露
|
||||||
|
}.ToImmutableHashSet();
|
||||||
|
|
||||||
|
private static readonly ImmutableHashSet<MaterialId> TuesdayFridayItemsInner = new HashSet<MaterialId>
|
||||||
|
{
|
||||||
|
104304, 104305, 104306, // 「抗争」
|
||||||
|
104313, 104314, 104315, // 「勤劳」
|
||||||
|
104323, 104324, 104325, // 「风雅」
|
||||||
|
104332, 104333, 104334, // 「巧思」
|
||||||
|
114005, 114006, 114007, 114008, // 凛风奔狼
|
||||||
|
114017, 114018, 114019, 114020, // 雾海云间
|
||||||
|
114029, 114030, 114031, 114032, // 鸣神御灵
|
||||||
|
114041, 114042, 114043, 114044, // 绿洲花园
|
||||||
|
}.ToImmutableHashSet();
|
||||||
|
|
||||||
|
private static readonly ImmutableHashSet<MaterialId> WednesdaySaturdayItemsInner = new HashSet<MaterialId>
|
||||||
|
{
|
||||||
|
104307, 104308, 104309, // 「诗文」
|
||||||
|
104316, 104317, 104318, // 「黄金」
|
||||||
|
104326, 104327, 104328, // 「天光」
|
||||||
|
104335, 104336, 104337, // 「笃行」
|
||||||
|
114009, 114010, 114011, 114012, // 狮牙斗士
|
||||||
|
114021, 114022, 114023, 114024, // 漆黑陨铁
|
||||||
|
114033, 114034, 114035, 114036, // 今昔剧画
|
||||||
|
114045, 114046, 114047, 114048, // 谧林涓露
|
||||||
|
}.ToImmutableHashSet();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 周一/周四
|
||||||
|
/// </summary>
|
||||||
|
public static ImmutableHashSet<MaterialId> MondayThursdayItems { get => MondayThursdayItemsInner; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 周二/周五
|
||||||
|
/// </summary>
|
||||||
|
public static ImmutableHashSet<MaterialId> TuesdayFridayItems { get => TuesdayFridayItemsInner; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 周三/周六
|
||||||
|
/// </summary>
|
||||||
|
public static ImmutableHashSet<MaterialId> WednesdaySaturdayItems { get => WednesdaySaturdayItemsInner; }
|
||||||
|
}
|
||||||
@@ -17,6 +17,11 @@ internal sealed class Monster
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public MonsterId Id { get; set; }
|
public MonsterId Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 描述 Id
|
||||||
|
/// </summary>
|
||||||
|
public MonsterDescribeId DescribeId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 内部代号
|
/// 内部代号
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -60,10 +65,11 @@ internal sealed class Monster
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 生长曲线
|
/// 生长曲线
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Dictionary<FightProperty, GrowCurveType> GrowCurves { get; set; } = default!;
|
public List<TypeValue<FightProperty, GrowCurveType>> GrowCurves { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 养成物品视图
|
/// 养成物品视图
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<Display>? DropsView { get; set; }
|
[JsonIgnore]
|
||||||
|
public List<DisplayItem>? DropsView { get; set; }
|
||||||
}
|
}
|
||||||
@@ -12,6 +12,8 @@ namespace Snap.Hutao.Model.Metadata;
|
|||||||
[HighQuality]
|
[HighQuality]
|
||||||
internal sealed class Promote
|
internal sealed class Promote
|
||||||
{
|
{
|
||||||
|
private Dictionary<FightProperty, float>? addPropertyMap;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Id
|
/// Id
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -20,10 +22,18 @@ internal sealed class Promote
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 突破等级
|
/// 突破等级
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Level { get; set; }
|
public PromoteLevel Level { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 增加的属性
|
/// 增加的属性
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Dictionary<FightProperty, float> AddProperties { get; set; } = default!;
|
public List<TypeValue<FightProperty, float>> AddProperties { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 属性映射
|
||||||
|
/// </summary>
|
||||||
|
public Dictionary<FightProperty, float> AddPropertyMap
|
||||||
|
{
|
||||||
|
get => addPropertyMap ??= AddProperties.ToDictionary(a => a.Type, a => a.Value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -20,7 +20,7 @@ internal sealed class Reliquary
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 允许出现的等级
|
/// 允许出现的等级
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ItemQuality RankLevel { get; set; } = default!;
|
public QualityType RankLevel { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 套装Id
|
/// 套装Id
|
||||||
|
|||||||
@@ -0,0 +1,109 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
|
using Snap.Hutao.Model.Primitive;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Model.Metadata.Reliquary;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 圣遗物词条权重
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class ReliquaryAffixWeight
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 角色 Id
|
||||||
|
/// </summary>
|
||||||
|
public AvatarId AvatarId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 生命值
|
||||||
|
/// </summary>
|
||||||
|
public float HpPercent { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 攻击力
|
||||||
|
/// </summary>
|
||||||
|
public float AttackPercent { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 防御力
|
||||||
|
/// </summary>
|
||||||
|
public float DefensePercent { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 暴击率
|
||||||
|
/// </summary>
|
||||||
|
public float Critical { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 暴击伤害
|
||||||
|
/// </summary>
|
||||||
|
public float CriticalHurt { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 元素精通
|
||||||
|
/// </summary>
|
||||||
|
public float ElementMastery { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 元素充能效率
|
||||||
|
/// </summary>
|
||||||
|
public float ChargeEfficiency { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 治疗加成
|
||||||
|
/// </summary>
|
||||||
|
public float HealAdd { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 物理伤害加成
|
||||||
|
/// </summary>
|
||||||
|
public float PhysicalAddHurt { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 伤害加成
|
||||||
|
/// </summary>
|
||||||
|
public float AddHurt { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 元素类型
|
||||||
|
/// </summary>
|
||||||
|
public ElementType ElementType { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取权重
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fightProperty">属性</param>
|
||||||
|
/// <returns>权重</returns>
|
||||||
|
public float this[FightProperty fightProperty]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if ((ElementType == ElementType.Fire && fightProperty == FightProperty.FIGHT_PROP_FIRE_ADD_HURT) ||
|
||||||
|
(ElementType == ElementType.Water && fightProperty == FightProperty.FIGHT_PROP_WATER_ADD_HURT) ||
|
||||||
|
(ElementType == ElementType.Grass && fightProperty == FightProperty.FIGHT_PROP_GRASS_ADD_HURT) ||
|
||||||
|
(ElementType == ElementType.Electric && fightProperty == FightProperty.FIGHT_PROP_ELEC_ADD_HURT) ||
|
||||||
|
(ElementType == ElementType.Ice && fightProperty == FightProperty.FIGHT_PROP_ICE_ADD_HURT) ||
|
||||||
|
(ElementType == ElementType.Wind && fightProperty == FightProperty.FIGHT_PROP_WIND_ADD_HURT) ||
|
||||||
|
(ElementType == ElementType.Rock && fightProperty == FightProperty.FIGHT_PROP_ROCK_ADD_HURT))
|
||||||
|
{
|
||||||
|
return AddHurt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fightProperty switch
|
||||||
|
{
|
||||||
|
FightProperty.FIGHT_PROP_HP_PERCENT => HpPercent,
|
||||||
|
FightProperty.FIGHT_PROP_ATTACK_PERCENT => AttackPercent,
|
||||||
|
FightProperty.FIGHT_PROP_DEFENSE_PERCENT => DefensePercent,
|
||||||
|
FightProperty.FIGHT_PROP_CRITICAL => Critical,
|
||||||
|
FightProperty.FIGHT_PROP_CRITICAL_HURT => CriticalHurt,
|
||||||
|
FightProperty.FIGHT_PROP_ELEMENT_MASTERY => ElementMastery,
|
||||||
|
FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY => ChargeEfficiency,
|
||||||
|
FightProperty.FIGHT_PROP_HEALED_ADD => HealAdd,
|
||||||
|
FightProperty.FIGHT_PROP_PHYSICAL_ADD_HURT => PhysicalAddHurt,
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Model.Metadata.Reliquary;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 属性映射
|
||||||
|
/// </summary>
|
||||||
|
internal sealed partial class ReliquaryMainAffixLevel
|
||||||
|
{
|
||||||
|
private Dictionary<FightProperty, float>? propertyMap;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 属性映射
|
||||||
|
/// </summary>
|
||||||
|
public Dictionary<FightProperty, float> PropertyMap
|
||||||
|
{
|
||||||
|
get => propertyMap ??= Properties.ToDictionary(t => t.Type, t => t.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,20 +9,20 @@ namespace Snap.Hutao.Model.Metadata.Reliquary;
|
|||||||
/// 圣遗物等级
|
/// 圣遗物等级
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HighQuality]
|
[HighQuality]
|
||||||
internal sealed class ReliquaryLevel
|
internal sealed partial class ReliquaryMainAffixLevel
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 品质
|
/// 品质
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ItemQuality Quality { get; set; }
|
public QualityType Rank { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 等级 1-21
|
/// 等级 1-21
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Level { get; set; }
|
public uint Level { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 属性
|
/// 属性
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Dictionary<FightProperty, float> Properties { get; set; } = default!;
|
public List<TypeValue<FightProperty, float>> Properties { get; set; } = default!;
|
||||||
}
|
}
|
||||||
@@ -14,7 +14,7 @@ internal sealed class ReliquarySet
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 套装Id
|
/// 套装Id
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int SetId { get; set; }
|
public ReliquarySetId SetId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 装备被动Id
|
/// 装备被动Id
|
||||||
|
|||||||
@@ -9,12 +9,12 @@ namespace Snap.Hutao.Model.Metadata.Reliquary;
|
|||||||
/// 圣遗物突破属性
|
/// 圣遗物突破属性
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HighQuality]
|
[HighQuality]
|
||||||
internal sealed class ReliquaryAffix : ReliquaryMainAffix
|
internal sealed class ReliquarySubAffix : ReliquaryMainAffix
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Id
|
/// Id
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public new ReliquaryAffixId Id { get; set; }
|
public new ReliquarySubAffixId Id { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 值
|
/// 值
|
||||||
32
src/Snap.Hutao/Snap.Hutao/Model/Metadata/Tower/TowerFloor.cs
Normal file
32
src/Snap.Hutao/Snap.Hutao/Model/Metadata/Tower/TowerFloor.cs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Model.Primitive;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Model.Metadata.Tower;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 深渊 层
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class TowerFloor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Id
|
||||||
|
/// </summary>
|
||||||
|
public TowerFloorId Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 编号 [1-12]
|
||||||
|
/// </summary>
|
||||||
|
public uint Index { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 深渊间分组编号
|
||||||
|
/// </summary>
|
||||||
|
public TowerLevelGroupId LevelGroupId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 背景图片
|
||||||
|
/// </summary>
|
||||||
|
public string Background { get; set; } = default!;
|
||||||
|
}
|
||||||
42
src/Snap.Hutao/Snap.Hutao/Model/Metadata/Tower/TowerLevel.cs
Normal file
42
src/Snap.Hutao/Snap.Hutao/Model/Metadata/Tower/TowerLevel.cs
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Model.Primitive;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Model.Metadata.Tower;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 深渊 间
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class TowerLevel
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Id
|
||||||
|
/// </summary>
|
||||||
|
public TowerLevelId Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 深渊间分组编号
|
||||||
|
/// </summary>
|
||||||
|
public TowerLevelGroupId GroupId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 编号
|
||||||
|
/// </summary>
|
||||||
|
public uint Index { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 怪物等级
|
||||||
|
/// </summary>
|
||||||
|
public uint MonsterLevel { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 上半怪物预览
|
||||||
|
/// </summary>
|
||||||
|
public List<MonsterId> FirstMonsters { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 下半怪物预览
|
||||||
|
/// </summary>
|
||||||
|
public List<MonsterId> SecondMonsters { get; set; } = default!;
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Model.Primitive;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Model.Metadata.Tower;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 深渊 计划
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class TowerSchedule
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 计划 Id
|
||||||
|
/// </summary>
|
||||||
|
public TowerScheduleId Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 层 Id 表
|
||||||
|
/// </summary>
|
||||||
|
public List<TowerFloorId> FloorIds { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 开始时间
|
||||||
|
/// </summary>
|
||||||
|
public DateTimeOffset Open { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 结束时间
|
||||||
|
/// </summary>
|
||||||
|
public DateTimeOffset Close { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 渊月祝福
|
||||||
|
/// </summary>
|
||||||
|
public string BuffName { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 描述
|
||||||
|
/// </summary>
|
||||||
|
public List<string> Descriptions { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 图标
|
||||||
|
/// </summary>
|
||||||
|
public string Icon { get; set; } = default!;
|
||||||
|
}
|
||||||
33
src/Snap.Hutao/Snap.Hutao/Model/Metadata/TypeValue.cs
Normal file
33
src/Snap.Hutao/Snap.Hutao/Model/Metadata/TypeValue.cs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Model.Metadata;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 类型与值
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TType">类型</typeparam>
|
||||||
|
/// <typeparam name="TValue">值</typeparam>
|
||||||
|
internal class TypeValue<TType, TValue>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 构造一个新的类型与值
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">类型</param>
|
||||||
|
/// <param name="value">值</param>
|
||||||
|
public TypeValue(TType type, TValue value)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 类型
|
||||||
|
/// </summary>
|
||||||
|
public TType Type { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 值
|
||||||
|
/// </summary>
|
||||||
|
public TValue Value { get; set; }
|
||||||
|
}
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
|
||||||
// Licensed under the MIT license.
|
|
||||||
|
|
||||||
using Snap.Hutao.Model.Intrinsic;
|
|
||||||
|
|
||||||
namespace Snap.Hutao.Model.Metadata.Weapon;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 生长曲线与值
|
|
||||||
/// </summary>
|
|
||||||
[HighQuality]
|
|
||||||
internal sealed class GrowCurveTypeValue
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 类型
|
|
||||||
/// </summary>
|
|
||||||
public GrowCurveType Type { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 值
|
|
||||||
/// </summary>
|
|
||||||
public float Value { get; set; }
|
|
||||||
}
|
|
||||||
@@ -23,7 +23,7 @@ internal sealed partial class Weapon : IStatisticsItemSource, ISummaryItemSource
|
|||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public ItemQuality Quality
|
public QualityType Quality
|
||||||
{
|
{
|
||||||
get => RankLevel;
|
get => RankLevel;
|
||||||
}
|
}
|
||||||
@@ -31,7 +31,7 @@ internal sealed partial class Weapon : IStatisticsItemSource, ISummaryItemSource
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 最大等级
|
/// 最大等级
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal int MaxLevel { get => ((int)Quality) >= 3 ? 90 : 70; }
|
internal uint MaxLevel { get => ((int)Quality) >= 3 ? 90U : 70U; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ICalculableWeapon ToCalculable()
|
public ICalculableWeapon ToCalculable()
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ internal sealed partial class Weapon
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 等级
|
/// 等级
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ItemQuality RankLevel { get; set; }
|
public QualityType RankLevel { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 名称
|
/// 名称
|
||||||
@@ -55,7 +55,7 @@ internal sealed partial class Weapon
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 生长曲线
|
/// 生长曲线
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Dictionary<FightProperty, GrowCurveTypeValue> GrowCurves { get; set; } = default!;
|
public List<WeaponTypeValue> GrowCurves { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 被动信息, 无被动的武器为 <see langword="null"/>
|
/// 被动信息, 无被动的武器为 <see langword="null"/>
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Model.Metadata.Weapon;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 武器曲线值
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class WeaponTypeValue : TypeValue<FightProperty, GrowCurveType>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 构造一个新的武器曲线值
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">属性类型</param>
|
||||||
|
/// <param name="value">曲线类型</param>
|
||||||
|
/// <param name="initValue">初始值</param>
|
||||||
|
public WeaponTypeValue(FightProperty type, GrowCurveType value, float initValue)
|
||||||
|
: base(type, value)
|
||||||
|
{
|
||||||
|
InitValue = initValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 初始值
|
||||||
|
/// </summary>
|
||||||
|
public float InitValue { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using System.Text.Json.Serialization.Metadata;
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Model.Primitive.Converter;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Id 转换器
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TWrapper">包装类型</typeparam>
|
||||||
|
internal unsafe sealed class IdentityConverter<TWrapper> : JsonConverter<TWrapper>
|
||||||
|
where TWrapper : unmanaged
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override TWrapper Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
uint value = JsonSerializer.Deserialize<uint>(ref reader, options);
|
||||||
|
return *(TWrapper*)&value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override TWrapper ReadAsPropertyName(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
if (reader.TokenType == JsonTokenType.PropertyName)
|
||||||
|
{
|
||||||
|
string? value = reader.GetString();
|
||||||
|
_ = uint.TryParse(value,out uint result);
|
||||||
|
return *(TWrapper*)&result;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new JsonException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override void Write(Utf8JsonWriter writer, TWrapper value, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
JsonSerializer.Serialize(writer, *(uint*)&value, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override void WriteAsPropertyName(Utf8JsonWriter writer, TWrapper value, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
writer.WritePropertyName((*(uint*)&value).ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -34,7 +34,7 @@ internal sealed partial class AchievementService : IAchievementService
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public List<AchievementView> GetAchievements(AchievementArchive archive, List<MetadataAchievement> metadata)
|
public List<AchievementView> GetAchievements(AchievementArchive archive, List<MetadataAchievement> metadata)
|
||||||
{
|
{
|
||||||
Dictionary<int, EntityAchievement> entityMap;
|
Dictionary<AchievementId, EntityAchievement> entityMap;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||||
@@ -43,7 +43,7 @@ internal sealed partial class AchievementService : IAchievementService
|
|||||||
entityMap = appDbContext.Achievements
|
entityMap = appDbContext.Achievements
|
||||||
.Where(a => a.ArchiveId == archive.InnerId)
|
.Where(a => a.ArchiveId == archive.InnerId)
|
||||||
.AsEnumerable()
|
.AsEnumerable()
|
||||||
.ToDictionary(a => a.Id);
|
.ToDictionary(a => (AchievementId)a.Id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (ArgumentException ex)
|
catch (ArgumentException ex)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
using Snap.Hutao.Core.Database;
|
using Snap.Hutao.Core.Database;
|
||||||
using Snap.Hutao.Model.Entity.Database;
|
using Snap.Hutao.Model.Entity.Database;
|
||||||
using Snap.Hutao.Model.Metadata;
|
using Snap.Hutao.Model.Metadata;
|
||||||
|
using Snap.Hutao.Model.Primitive;
|
||||||
using Snap.Hutao.Service.AvatarInfo.Transformer;
|
using Snap.Hutao.Service.AvatarInfo.Transformer;
|
||||||
using Snap.Hutao.Service.Metadata;
|
using Snap.Hutao.Service.Metadata;
|
||||||
using Snap.Hutao.ViewModel.User;
|
using Snap.Hutao.ViewModel.User;
|
||||||
@@ -202,7 +203,7 @@ internal sealed partial class AvatarInfoDbBulkOperation
|
|||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static void AddOrUpdateAvatarInfo<TSource>(ModelAvatarInfo? entity, int avatarId, string uid, AppDbContext appDbContext, IAvatarInfoTransformer<TSource> transformer, TSource source)
|
private static void AddOrUpdateAvatarInfo<TSource>(ModelAvatarInfo? entity, AvatarId avatarId, string uid, AppDbContext appDbContext, IAvatarInfoTransformer<TSource> transformer, TSource source)
|
||||||
{
|
{
|
||||||
if (entity == null)
|
if (entity == null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ internal sealed class AffixWeight : Dictionary<FightProperty, float>
|
|||||||
/// <param name="heal">治疗加成</param>
|
/// <param name="heal">治疗加成</param>
|
||||||
/// <param name="name">名称</param>
|
/// <param name="name">名称</param>
|
||||||
public AffixWeight(
|
public AffixWeight(
|
||||||
int avatarId,
|
uint avatarId,
|
||||||
float hp,
|
float hp,
|
||||||
float atk,
|
float atk,
|
||||||
float def,
|
float def,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
using Snap.Hutao.Model.Intrinsic;
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
|
using Snap.Hutao.Model.Primitive;
|
||||||
using Snap.Hutao.Model.Metadata.Converter;
|
using Snap.Hutao.Model.Metadata.Converter;
|
||||||
using Snap.Hutao.ViewModel.AvatarProperty;
|
using Snap.Hutao.ViewModel.AvatarProperty;
|
||||||
using Snap.Hutao.Web.Enka.Model;
|
using Snap.Hutao.Web.Enka.Model;
|
||||||
@@ -79,7 +80,7 @@ internal sealed class SummaryAvatarFactory
|
|||||||
Model.Metadata.Avatar.Costume costume = avatar.Costumes.Single(c => c.Id == avatarInfo.CostumeId.Value);
|
Model.Metadata.Avatar.Costume costume = avatar.Costumes.Single(c => c.Id == avatarInfo.CostumeId.Value);
|
||||||
|
|
||||||
// Set to costume icon
|
// Set to costume icon
|
||||||
propertyAvatar.Icon = AvatarIconConverter.IconNameToUri(costume.Icon);
|
propertyAvatar.Icon = AvatarIconConverter.IconNameToUri(costume.FrontIcon);
|
||||||
propertyAvatar.SideIcon = AvatarIconConverter.IconNameToUri(costume.SideIcon);
|
propertyAvatar.SideIcon = AvatarIconConverter.IconNameToUri(costume.SideIcon);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -116,9 +117,9 @@ internal sealed class SummaryAvatarFactory
|
|||||||
{
|
{
|
||||||
MetadataWeapon weapon = metadataContext.IdWeaponMap[equip.ItemId];
|
MetadataWeapon weapon = metadataContext.IdWeaponMap[equip.ItemId];
|
||||||
|
|
||||||
// AffixMap can be empty when it's a white weapon.
|
// AffixMap can be null when it's a white weapon.
|
||||||
KeyValuePair<string, int>? idLevel = equip.Weapon!.AffixMap?.Single();
|
KeyValuePair<EquipAffixId, WeaponAffixLevel>? idLevel = equip.Weapon!.AffixMap?.Single();
|
||||||
int affixLevel = idLevel?.Value ?? 0;
|
uint affixLevel = idLevel?.Value ?? 0U;
|
||||||
|
|
||||||
WeaponStat? mainStat = equip.Flat.WeaponStats?.ElementAtOrDefault(0);
|
WeaponStat? mainStat = equip.Flat.WeaponStats?.ElementAtOrDefault(0);
|
||||||
WeaponStat? subStat = equip.Flat.WeaponStats?.ElementAtOrDefault(1);
|
WeaponStat? subStat = equip.Flat.WeaponStats?.ElementAtOrDefault(1);
|
||||||
@@ -145,7 +146,7 @@ internal sealed class SummaryAvatarFactory
|
|||||||
Description = weapon.Description,
|
Description = weapon.Description,
|
||||||
|
|
||||||
// EquipBase
|
// EquipBase
|
||||||
Level = $"Lv.{equip.Weapon!.Level}",
|
Level = $"Lv.{equip.Weapon!.Level.Value}",
|
||||||
Quality = weapon.Quality,
|
Quality = weapon.Quality,
|
||||||
MainProperty = mainStat != null ? FightPropertyFormat.ToNameValue(mainStat.AppendPropId, mainStat.StatValue) : default!,
|
MainProperty = mainStat != null ? FightPropertyFormat.ToNameValue(mainStat.AppendPropId, mainStat.StatValue) : default!,
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ internal sealed partial class SummaryFactory : ISummaryFactory
|
|||||||
IdAvatarMap = await metadataService.GetIdToAvatarMapAsync(token).ConfigureAwait(false),
|
IdAvatarMap = await metadataService.GetIdToAvatarMapAsync(token).ConfigureAwait(false),
|
||||||
IdWeaponMap = await metadataService.GetIdToWeaponMapAsync(token).ConfigureAwait(false),
|
IdWeaponMap = await metadataService.GetIdToWeaponMapAsync(token).ConfigureAwait(false),
|
||||||
IdRelicMainPropMap = await metadataService.GetIdToReliquaryMainPropertyMapAsync(token).ConfigureAwait(false),
|
IdRelicMainPropMap = await metadataService.GetIdToReliquaryMainPropertyMapAsync(token).ConfigureAwait(false),
|
||||||
IdReliquaryAffixMap = await metadataService.GetIdToReliquaryAffixMapAsync(token).ConfigureAwait(false),
|
IdReliquarySubAffixMap = await metadataService.GetIdToReliquarySubAffixMapAsync(token).ConfigureAwait(false),
|
||||||
ReliqueryLevels = await metadataService.GetReliquaryLevelsAsync(token).ConfigureAwait(false),
|
ReliqueryLevels = await metadataService.GetReliquaryLevelsAsync(token).ConfigureAwait(false),
|
||||||
Reliquaries = await metadataService.GetReliquariesAsync(token).ConfigureAwait(false),
|
Reliquaries = await metadataService.GetReliquariesAsync(token).ConfigureAwait(false),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -39,29 +39,26 @@ internal static class SummaryHelper
|
|||||||
/// <param name="proudSkillExtraLevelMap">额外提升等级映射</param>
|
/// <param name="proudSkillExtraLevelMap">额外提升等级映射</param>
|
||||||
/// <param name="proudSkills">技能列表</param>
|
/// <param name="proudSkills">技能列表</param>
|
||||||
/// <returns>技能</returns>
|
/// <returns>技能</returns>
|
||||||
public static List<SkillView> CreateSkills(Dictionary<string, int> skillLevelMap, Dictionary<string, int>? proudSkillExtraLevelMap, List<ProudableSkill> proudSkills)
|
public static List<SkillView> CreateSkills(Dictionary<SkillId, SkillLevel> skillLevelMap, Dictionary<SkillGroupId, SkillLevel>? proudSkillExtraLevelMap, List<ProudableSkill> proudSkills)
|
||||||
{
|
{
|
||||||
if (skillLevelMap == null)
|
if (skillLevelMap == null)
|
||||||
{
|
{
|
||||||
return new();
|
return new();
|
||||||
}
|
}
|
||||||
|
|
||||||
Dictionary<string, int> skillExtraLeveledMap = new(skillLevelMap);
|
Dictionary<SkillId, SkillLevel> skillExtraLeveledMap = new(skillLevelMap);
|
||||||
|
|
||||||
if (proudSkillExtraLevelMap != null)
|
if (proudSkillExtraLevelMap != null)
|
||||||
{
|
{
|
||||||
foreach ((string skillGroupIdString, int extraLevel) in proudSkillExtraLevelMap)
|
foreach ((SkillGroupId groupId, SkillLevel extraLevel) in proudSkillExtraLevelMap)
|
||||||
{
|
{
|
||||||
SkillGroupId skillGroupId = int.Parse(skillGroupIdString);
|
skillExtraLeveledMap.IncreaseValue(proudSkills.Single(p => p.GroupId == groupId).Id, extraLevel);
|
||||||
SkillId skillId = proudSkills.Single(p => p.GroupId == skillGroupId).Id;
|
|
||||||
|
|
||||||
skillExtraLeveledMap.Increase($"{skillId.Value}", extraLevel);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return proudSkills.SelectList(proudableSkill =>
|
return proudSkills.SelectList(proudableSkill =>
|
||||||
{
|
{
|
||||||
string skillId = $"{proudableSkill.Id.Value}";
|
SkillId skillId = proudableSkill.Id;
|
||||||
|
|
||||||
return new SkillView()
|
return new SkillView()
|
||||||
{
|
{
|
||||||
@@ -81,10 +78,10 @@ internal static class SummaryHelper
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="appendId">属性Id</param>
|
/// <param name="appendId">属性Id</param>
|
||||||
/// <returns>最大属性Id</returns>
|
/// <returns>最大属性Id</returns>
|
||||||
public static int GetAffixMaxId(int appendId)
|
public static ReliquarySubAffixId GetAffixMaxId(in ReliquarySubAffixId appendId)
|
||||||
{
|
{
|
||||||
int value = appendId / 100000;
|
uint value = (uint)appendId / 100000U;
|
||||||
int max = value switch
|
uint max = value switch
|
||||||
{
|
{
|
||||||
1 => 2,
|
1 => 2,
|
||||||
2 => 3,
|
2 => 3,
|
||||||
@@ -100,10 +97,10 @@ internal static class SummaryHelper
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="appendId">id</param>
|
/// <param name="appendId">id</param>
|
||||||
/// <returns>分数</returns>
|
/// <returns>分数</returns>
|
||||||
public static float GetPercentSubAffixScore(int appendId)
|
public static float GetPercentSubAffixScore(ReliquarySubAffixId appendId)
|
||||||
{
|
{
|
||||||
int maxId = GetAffixMaxId(appendId);
|
uint maxId = GetAffixMaxId(appendId);
|
||||||
int delta = maxId - appendId;
|
uint delta = maxId - appendId;
|
||||||
|
|
||||||
return (maxId / 100000, delta) switch
|
return (maxId / 100000, delta) switch
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -34,12 +34,12 @@ internal sealed class SummaryMetadataContext
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 圣遗物副属性映射
|
/// 圣遗物副属性映射
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Dictionary<ReliquaryAffixId, ReliquaryAffix> IdReliquaryAffixMap { get; set; } = default!;
|
public Dictionary<ReliquarySubAffixId, ReliquarySubAffix> IdReliquarySubAffixMap { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 圣遗物等级
|
/// 圣遗物等级
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<ReliquaryLevel> ReliqueryLevels { get; set; } = default!;
|
public List<ReliquaryMainAffixLevel> ReliqueryLevels { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 圣遗物
|
/// 圣遗物
|
||||||
|
|||||||
@@ -5,11 +5,12 @@ using Snap.Hutao.Model.Intrinsic;
|
|||||||
using Snap.Hutao.Model.Intrinsic.Format;
|
using Snap.Hutao.Model.Intrinsic.Format;
|
||||||
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.Model.Primitive;
|
||||||
using Snap.Hutao.ViewModel.AvatarProperty;
|
using Snap.Hutao.ViewModel.AvatarProperty;
|
||||||
using Snap.Hutao.Web.Enka.Model;
|
using Snap.Hutao.Web.Enka.Model;
|
||||||
using System.Runtime.InteropServices;
|
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.ReliquarySubAffix;
|
||||||
using ModelAvatarInfo = Snap.Hutao.Web.Enka.Model.AvatarInfo;
|
using ModelAvatarInfo = Snap.Hutao.Web.Enka.Model.AvatarInfo;
|
||||||
using PropertyReliquary = Snap.Hutao.ViewModel.AvatarProperty.ReliquaryView;
|
using PropertyReliquary = Snap.Hutao.ViewModel.AvatarProperty.ReliquaryView;
|
||||||
|
|
||||||
@@ -67,11 +68,10 @@ internal sealed class SummaryReliquaryFactory
|
|||||||
result.PrimarySubProperties = new(span[..^affixCount].ToArray());
|
result.PrimarySubProperties = new(span[..^affixCount].ToArray());
|
||||||
result.SecondarySubProperties = new(span[^affixCount..].ToArray());
|
result.SecondarySubProperties = new(span[^affixCount..].ToArray());
|
||||||
result.ComposedSubProperties = equip.Flat.ReliquarySubstats!.SelectList(CreateComposedSubProperty);
|
result.ComposedSubProperties = equip.Flat.ReliquarySubstats!.SelectList(CreateComposedSubProperty);
|
||||||
|
ReliquaryMainAffixLevel relicLevel = metadataContext.ReliqueryLevels.Single(r => r.Level == equip.Reliquary!.Level && r.Rank == reliquary.RankLevel);
|
||||||
ReliquaryLevel relicLevel = metadataContext.ReliqueryLevels.Single(r => r.Level == equip.Reliquary!.Level && r.Quality == reliquary.RankLevel);
|
|
||||||
FightProperty property = metadataContext.IdRelicMainPropMap[equip.Reliquary.MainPropId];
|
FightProperty property = metadataContext.IdRelicMainPropMap[equip.Reliquary.MainPropId];
|
||||||
|
|
||||||
result.MainProperty = FightPropertyFormat.ToNameValue(property, relicLevel.Properties[property]);
|
result.MainProperty = FightPropertyFormat.ToNameValue(property, relicLevel.PropertyMap[property]);
|
||||||
result.Score = ScoreReliquary(property, reliquary, relicLevel, subProperty);
|
result.Score = ScoreReliquary(property, reliquary, relicLevel, subProperty);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,46 +81,46 @@ internal sealed class SummaryReliquaryFactory
|
|||||||
private int GetSecondaryAffixCount(MetadataReliquary reliquary)
|
private int GetSecondaryAffixCount(MetadataReliquary reliquary)
|
||||||
{
|
{
|
||||||
// 强化词条个数
|
// 强化词条个数
|
||||||
return (reliquary.RankLevel, equip.Reliquary!.Level) switch
|
return (reliquary.RankLevel, equip.Reliquary!.Level.Value) switch
|
||||||
{
|
{
|
||||||
(ItemQuality.QUALITY_ORANGE, > 20) => 5,
|
(QualityType.QUALITY_ORANGE, > 20U) => 5,
|
||||||
(ItemQuality.QUALITY_ORANGE, > 16) => 4,
|
(QualityType.QUALITY_ORANGE, > 16U) => 4,
|
||||||
(ItemQuality.QUALITY_ORANGE, > 12) => 3,
|
(QualityType.QUALITY_ORANGE, > 12U) => 3,
|
||||||
(ItemQuality.QUALITY_ORANGE, > 8) => 2,
|
(QualityType.QUALITY_ORANGE, > 8U) => 2,
|
||||||
(ItemQuality.QUALITY_ORANGE, > 4) => 1,
|
(QualityType.QUALITY_ORANGE, > 4U) => 1,
|
||||||
(ItemQuality.QUALITY_ORANGE, _) => 0,
|
(QualityType.QUALITY_ORANGE, _) => 0,
|
||||||
|
|
||||||
(ItemQuality.QUALITY_PURPLE, > 16) => 4,
|
(QualityType.QUALITY_PURPLE, > 16U) => 4,
|
||||||
(ItemQuality.QUALITY_PURPLE, > 12) => 3,
|
(QualityType.QUALITY_PURPLE, > 12U) => 3,
|
||||||
(ItemQuality.QUALITY_PURPLE, > 8) => 2,
|
(QualityType.QUALITY_PURPLE, > 8U) => 2,
|
||||||
(ItemQuality.QUALITY_PURPLE, > 4) => 1,
|
(QualityType.QUALITY_PURPLE, > 4U) => 1,
|
||||||
(ItemQuality.QUALITY_PURPLE, _) => 0,
|
(QualityType.QUALITY_PURPLE, _) => 0,
|
||||||
|
|
||||||
(ItemQuality.QUALITY_BLUE, > 12) => 3,
|
(QualityType.QUALITY_BLUE, > 12U) => 3,
|
||||||
(ItemQuality.QUALITY_BLUE, > 8) => 2,
|
(QualityType.QUALITY_BLUE, > 8U) => 2,
|
||||||
(ItemQuality.QUALITY_BLUE, > 4) => 1,
|
(QualityType.QUALITY_BLUE, > 4U) => 1,
|
||||||
(ItemQuality.QUALITY_BLUE, _) => 0,
|
(QualityType.QUALITY_BLUE, _) => 0,
|
||||||
|
|
||||||
(ItemQuality.QUALITY_GREEN, > 4) => 1,
|
(QualityType.QUALITY_GREEN, > 4U) => 1,
|
||||||
(ItemQuality.QUALITY_GREEN, _) => 0,
|
(QualityType.QUALITY_GREEN, _) => 0,
|
||||||
|
|
||||||
(ItemQuality.QUALITY_WHITE, > 4) => 1,
|
(QualityType.QUALITY_WHITE, > 4U) => 1,
|
||||||
(ItemQuality.QUALITY_WHITE, _) => 0,
|
(QualityType.QUALITY_WHITE, _) => 0,
|
||||||
|
|
||||||
_ => 0,
|
_ => 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private float ScoreReliquary(FightProperty property, MetadataReliquary reliquary, ReliquaryLevel relicLevel, List<ReliquarySubProperty> subProperties)
|
private float ScoreReliquary(FightProperty property, MetadataReliquary reliquary, ReliquaryMainAffixLevel relicLevel, List<ReliquarySubProperty> subProperties)
|
||||||
{
|
{
|
||||||
// 沙 杯 头
|
// 沙 杯 头
|
||||||
// equip.Flat.EquipType is EquipType.EQUIP_SHOES or EquipType.EQUIP_RING or EquipType.EQUIP_DRESS
|
// equip.Flat.EquipType is EquipType.EQUIP_SHOES or EquipType.EQUIP_RING or EquipType.EQUIP_DRESS
|
||||||
if ((int)equip.Flat.EquipType > 3)
|
if ((int)equip.Flat.EquipType > 3)
|
||||||
{
|
{
|
||||||
AffixWeight weightConfig = GetAffixWeightForAvatarId();
|
AffixWeight weightConfig = GetAffixWeightForAvatarId();
|
||||||
ReliquaryLevel maxRelicLevel = metadataContext.ReliqueryLevels.Where(r => r.Quality == reliquary.RankLevel).MaxBy(r => r.Level)!;
|
ReliquaryMainAffixLevel maxRelicLevel = metadataContext.ReliqueryLevels.Where(r => r.Rank == reliquary.RankLevel).MaxBy(r => r.Level)!;
|
||||||
|
|
||||||
float percent = relicLevel.Properties[property] / maxRelicLevel.Properties[property];
|
float percent = relicLevel.PropertyMap[property] / maxRelicLevel.PropertyMap[property];
|
||||||
float baseScore = 8 * percent * weightConfig.GetValueOrDefault(property);
|
float baseScore = 8 * percent * weightConfig.GetValueOrDefault(property);
|
||||||
|
|
||||||
float score = subProperties.Sum(p => p.Score);
|
float score = subProperties.Sum(p => p.Score);
|
||||||
@@ -151,9 +151,10 @@ internal sealed class SummaryReliquaryFactory
|
|||||||
return new(substat.AppendPropId.GetLocalizedDescription(), valueFormatted, 0);
|
return new(substat.AppendPropId.GetLocalizedDescription(), valueFormatted, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ReliquarySubProperty CreateSubProperty(int appendPropId)
|
[SuppressMessage("", "SH002")]
|
||||||
|
private ReliquarySubProperty CreateSubProperty(ReliquarySubAffixId appendPropId)
|
||||||
{
|
{
|
||||||
MetadataReliquaryAffix affix = metadataContext.IdReliquaryAffixMap[appendPropId];
|
MetadataReliquaryAffix affix = metadataContext.IdReliquarySubAffixMap[appendPropId];
|
||||||
FightProperty property = affix.Type;
|
FightProperty property = affix.Type;
|
||||||
|
|
||||||
return new(
|
return new(
|
||||||
@@ -162,9 +163,9 @@ internal sealed class SummaryReliquaryFactory
|
|||||||
ScoreSubAffix(appendPropId));
|
ScoreSubAffix(appendPropId));
|
||||||
}
|
}
|
||||||
|
|
||||||
private float ScoreSubAffix(int appendId)
|
private float ScoreSubAffix(in ReliquarySubAffixId appendId)
|
||||||
{
|
{
|
||||||
MetadataReliquaryAffix affix = metadataContext.IdReliquaryAffixMap[appendId];
|
MetadataReliquaryAffix affix = metadataContext.IdReliquarySubAffixMap[appendId];
|
||||||
|
|
||||||
AffixWeight weightConfig = GetAffixWeightForAvatarId();
|
AffixWeight weightConfig = GetAffixWeightForAvatarId();
|
||||||
float weight = weightConfig.GetValueOrDefault(affix.Type) / 100F;
|
float weight = weightConfig.GetValueOrDefault(affix.Type) / 100F;
|
||||||
@@ -179,7 +180,7 @@ internal sealed class SummaryReliquaryFactory
|
|||||||
weight = weightConfig.GetValueOrDefault(affix.Type + 1) / 100F;
|
weight = weightConfig.GetValueOrDefault(affix.Type + 1) / 100F;
|
||||||
|
|
||||||
// 最大同属性百分比数值 最大同属性百分比Id 第四五位是战斗属性位
|
// 最大同属性百分比数值 最大同属性百分比Id 第四五位是战斗属性位
|
||||||
MetadataReliquaryAffix maxPercentAffix = metadataContext.IdReliquaryAffixMap[SummaryHelper.GetAffixMaxId(appendId + 10)];
|
MetadataReliquaryAffix maxPercentAffix = metadataContext.IdReliquarySubAffixMap[SummaryHelper.GetAffixMaxId(appendId + 10U)];
|
||||||
float equalScore = equalPercent / maxPercentAffix.Value;
|
float equalScore = equalPercent / maxPercentAffix.Value;
|
||||||
|
|
||||||
return weight * equalScore * 100;
|
return weight * equalScore * 100;
|
||||||
|
|||||||
@@ -1,6 +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.
|
||||||
|
|
||||||
|
using Snap.Hutao.Model.Primitive;
|
||||||
using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
||||||
|
|
||||||
namespace Snap.Hutao.Service.AvatarInfo.Transformer;
|
namespace Snap.Hutao.Service.AvatarInfo.Transformer;
|
||||||
@@ -16,6 +17,6 @@ internal sealed class CalculateAvatarDetailAvatarInfoTransformer : IAvatarInfoTr
|
|||||||
public void Transform(ref Web.Enka.Model.AvatarInfo avatarInfo, AvatarDetail source)
|
public void Transform(ref Web.Enka.Model.AvatarInfo avatarInfo, AvatarDetail source)
|
||||||
{
|
{
|
||||||
// update skills
|
// update skills
|
||||||
avatarInfo.SkillLevelMap = source.SkillList.ToDictionary(s => $"{s.Id}", s => s.LevelCurrent);
|
avatarInfo.SkillLevelMap = source.SkillList.ToDictionary(s => (SkillId)s.Id, s => (SkillLevel)s.LevelCurrent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,7 +57,10 @@ internal sealed class GameRecordCharacterAvatarInfoTransformer : IAvatarInfoTran
|
|||||||
equip.Weapon = new()
|
equip.Weapon = new()
|
||||||
{
|
{
|
||||||
Level = source.Weapon.Level,
|
Level = source.Weapon.Level,
|
||||||
AffixMap = new() { { $"1{source.Weapon.Id}", source.Weapon.AffixLevel - 1 }, },
|
AffixMap = new()
|
||||||
|
{
|
||||||
|
[100000 + source.Weapon.Id] = source.Weapon.AffixLevel - 1,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Special case here, don't set EQUIP_WEAPON
|
// Special case here, don't set EQUIP_WEAPON
|
||||||
|
|||||||
@@ -186,7 +186,7 @@ internal sealed partial class CultivationService : ICultivationService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async Task<bool> SaveConsumptionAsync(CultivateType type, int itemId, List<Web.Hoyolab.Takumi.Event.Calculate.Item> items)
|
public async Task<bool> SaveConsumptionAsync(CultivateType type, uint itemId, List<Web.Hoyolab.Takumi.Event.Calculate.Item> items)
|
||||||
{
|
{
|
||||||
if (items.Count == 0)
|
if (items.Count == 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ internal interface ICultivationService
|
|||||||
/// <param name="itemId">主Id</param>
|
/// <param name="itemId">主Id</param>
|
||||||
/// <param name="items">待存物品</param>
|
/// <param name="items">待存物品</param>
|
||||||
/// <returns>是否保存成功</returns>
|
/// <returns>是否保存成功</returns>
|
||||||
Task<bool> SaveConsumptionAsync(CultivateType type, int itemId, List<Item> items);
|
Task<bool> SaveConsumptionAsync(CultivateType type, uint itemId, List<Item> items);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 保存养成物品状态
|
/// 保存养成物品状态
|
||||||
|
|||||||
@@ -60,19 +60,19 @@ internal sealed partial class GachaStatisticsFactory : IGachaStatisticsFactory
|
|||||||
// It's an avatar
|
// It's an avatar
|
||||||
switch (item.ItemId.Place())
|
switch (item.ItemId.Place())
|
||||||
{
|
{
|
||||||
case 8:
|
case 8U:
|
||||||
{
|
{
|
||||||
Avatar avatar = context.IdAvatarMap[item.ItemId];
|
Avatar avatar = context.IdAvatarMap[item.ItemId];
|
||||||
|
|
||||||
bool isUp = false;
|
bool isUp = false;
|
||||||
switch (avatar.Quality)
|
switch (avatar.Quality)
|
||||||
{
|
{
|
||||||
case ItemQuality.QUALITY_ORANGE:
|
case QualityType.QUALITY_ORANGE:
|
||||||
orangeAvatarCounter.Increase(avatar);
|
orangeAvatarCounter.IncreaseOne(avatar);
|
||||||
isUp = targetHistoryWishBuilder?.IncreaseOrange(avatar) ?? false;
|
isUp = targetHistoryWishBuilder?.IncreaseOrange(avatar) ?? false;
|
||||||
break;
|
break;
|
||||||
case ItemQuality.QUALITY_PURPLE:
|
case QualityType.QUALITY_PURPLE:
|
||||||
purpleAvatarCounter.Increase(avatar);
|
purpleAvatarCounter.IncreaseOne(avatar);
|
||||||
targetHistoryWishBuilder?.IncreasePurple(avatar);
|
targetHistoryWishBuilder?.IncreasePurple(avatar);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -83,24 +83,24 @@ internal sealed partial class GachaStatisticsFactory : IGachaStatisticsFactory
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 5:
|
case 5U:
|
||||||
{
|
{
|
||||||
Weapon weapon = context.IdWeaponMap[item.ItemId];
|
Weapon weapon = context.IdWeaponMap[item.ItemId];
|
||||||
|
|
||||||
bool isUp = false;
|
bool isUp = false;
|
||||||
switch (weapon.RankLevel)
|
switch (weapon.RankLevel)
|
||||||
{
|
{
|
||||||
case ItemQuality.QUALITY_ORANGE:
|
case QualityType.QUALITY_ORANGE:
|
||||||
isUp = targetHistoryWishBuilder?.IncreaseOrange(weapon) ?? false;
|
isUp = targetHistoryWishBuilder?.IncreaseOrange(weapon) ?? false;
|
||||||
orangeWeaponCounter.Increase(weapon);
|
orangeWeaponCounter.IncreaseOne(weapon);
|
||||||
break;
|
break;
|
||||||
case ItemQuality.QUALITY_PURPLE:
|
case QualityType.QUALITY_PURPLE:
|
||||||
targetHistoryWishBuilder?.IncreasePurple(weapon);
|
targetHistoryWishBuilder?.IncreasePurple(weapon);
|
||||||
purpleWeaponCounter.Increase(weapon);
|
purpleWeaponCounter.IncreaseOne(weapon);
|
||||||
break;
|
break;
|
||||||
case ItemQuality.QUALITY_BLUE:
|
case QualityType.QUALITY_BLUE:
|
||||||
targetHistoryWishBuilder?.IncreaseBlue(weapon);
|
targetHistoryWishBuilder?.IncreaseBlue(weapon);
|
||||||
blueWeaponCounter.Increase(weapon);
|
blueWeaponCounter.IncreaseOne(weapon);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -73,15 +73,15 @@ internal sealed partial class GachaStatisticsSlimFactory : IGachaStatisticsSlimF
|
|||||||
{
|
{
|
||||||
switch (nameQuality.Quality)
|
switch (nameQuality.Quality)
|
||||||
{
|
{
|
||||||
case ItemQuality.QUALITY_ORANGE:
|
case QualityType.QUALITY_ORANGE:
|
||||||
orangeTracker = 0;
|
orangeTracker = 0;
|
||||||
++purpleTracker;
|
++purpleTracker;
|
||||||
break;
|
break;
|
||||||
case ItemQuality.QUALITY_PURPLE:
|
case QualityType.QUALITY_PURPLE:
|
||||||
++orangeTracker;
|
++orangeTracker;
|
||||||
purpleTracker = 0;
|
purpleTracker = 0;
|
||||||
break;
|
break;
|
||||||
case ItemQuality.QUALITY_BLUE:
|
case QualityType.QUALITY_BLUE:
|
||||||
++orangeTracker;
|
++orangeTracker;
|
||||||
++purpleTracker;
|
++purpleTracker;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -71,10 +71,10 @@ internal sealed class HistoryWishBuilder
|
|||||||
/// <returns>是否为Up物品</returns>
|
/// <returns>是否为Up物品</returns>
|
||||||
public bool IncreaseOrange(IStatisticsItemSource item)
|
public bool IncreaseOrange(IStatisticsItemSource item)
|
||||||
{
|
{
|
||||||
orangeCounter.Increase(item);
|
orangeCounter.IncreaseOne(item);
|
||||||
++totalCountTracker;
|
++totalCountTracker;
|
||||||
|
|
||||||
return orangeUpCounter.TryIncrease(item);
|
return orangeUpCounter.TryIncreaseOne(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -83,8 +83,8 @@ internal sealed class HistoryWishBuilder
|
|||||||
/// <param name="item">物品</param>
|
/// <param name="item">物品</param>
|
||||||
public void IncreasePurple(IStatisticsItemSource item)
|
public void IncreasePurple(IStatisticsItemSource item)
|
||||||
{
|
{
|
||||||
purpleUpCounter.TryIncrease(item);
|
purpleUpCounter.TryIncreaseOne(item);
|
||||||
purpleCounter.Increase(item);
|
purpleCounter.IncreaseOne(item);
|
||||||
++totalCountTracker;
|
++totalCountTracker;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,7 +94,7 @@ internal sealed class HistoryWishBuilder
|
|||||||
/// <param name="item">武器</param>
|
/// <param name="item">武器</param>
|
||||||
public void IncreaseBlue(IStatisticsItemSource item)
|
public void IncreaseBlue(IStatisticsItemSource item)
|
||||||
{
|
{
|
||||||
blueCounter.Increase(item);
|
blueCounter.IncreaseOne(item);
|
||||||
++totalCountTracker;
|
++totalCountTracker;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ internal sealed class TypedWishSummaryBuilder
|
|||||||
|
|
||||||
switch (source.Quality)
|
switch (source.Quality)
|
||||||
{
|
{
|
||||||
case ItemQuality.QUALITY_ORANGE:
|
case QualityType.QUALITY_ORANGE:
|
||||||
{
|
{
|
||||||
TrackMinMaxOrangePull(lastOrangePullTracker);
|
TrackMinMaxOrangePull(lastOrangePullTracker);
|
||||||
averageOrangePullTracker.Add(lastOrangePullTracker);
|
averageOrangePullTracker.Add(lastOrangePullTracker);
|
||||||
@@ -105,14 +105,14 @@ internal sealed class TypedWishSummaryBuilder
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ItemQuality.QUALITY_PURPLE:
|
case QualityType.QUALITY_PURPLE:
|
||||||
{
|
{
|
||||||
lastPurplePullTracker = 0;
|
lastPurplePullTracker = 0;
|
||||||
++totalPurplePullTracker;
|
++totalPurplePullTracker;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ItemQuality.QUALITY_BLUE:
|
case QualityType.QUALITY_BLUE:
|
||||||
{
|
{
|
||||||
++totalBluePullTracker;
|
++totalBluePullTracker;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -104,13 +104,13 @@ internal readonly struct GachaLogServiceContext
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="id">Id</param>
|
/// <param name="id">Id</param>
|
||||||
/// <returns>名称星级</returns>
|
/// <returns>名称星级</returns>
|
||||||
public INameQuality GetNameQualityByItemId(int id)
|
public INameQuality GetNameQualityByItemId(uint id)
|
||||||
{
|
{
|
||||||
int place = id.Place();
|
uint place = id.Place();
|
||||||
return place switch
|
return place switch
|
||||||
{
|
{
|
||||||
8 => IdAvatarMap![id],
|
8U => IdAvatarMap![id],
|
||||||
5 => IdWeaponMap![id],
|
5U => IdWeaponMap![id],
|
||||||
_ => throw Must.NeverHappen($"Id places: {place}"),
|
_ => throw Must.NeverHappen($"Id places: {place}"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -121,13 +121,13 @@ internal readonly struct GachaLogServiceContext
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="item">祈愿物品</param>
|
/// <param name="item">祈愿物品</param>
|
||||||
/// <returns>物品 Id</returns>
|
/// <returns>物品 Id</returns>
|
||||||
public int GetItemId(GachaLogItem item)
|
public uint GetItemId(GachaLogItem item)
|
||||||
{
|
{
|
||||||
return item.ItemType switch
|
return item.ItemType switch
|
||||||
{
|
{
|
||||||
"角色" => NameAvatarMap!.GetValueOrDefault(item.Name)?.Id ?? 0,
|
"角色" => NameAvatarMap!.GetValueOrDefault(item.Name)?.Id ?? 0,
|
||||||
"武器" => NameWeaponMap!.GetValueOrDefault(item.Name)?.Id ?? 0,
|
"武器" => NameWeaponMap!.GetValueOrDefault(item.Name)?.Id ?? 0,
|
||||||
_ => 0,
|
_ => 0U,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
|
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
|
||||||
using Snap.Hutao.Core.ExceptionService;
|
using Snap.Hutao.Core.ExceptionService;
|
||||||
using Snap.Hutao.Core.IO;
|
using Snap.Hutao.Core.IO;
|
||||||
|
using Snap.Hutao.Core.IO.Hashing;
|
||||||
using Snap.Hutao.Service.Notification;
|
using Snap.Hutao.Service.Notification;
|
||||||
using Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher;
|
using Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@@ -240,7 +241,7 @@ internal sealed partial class PackageConverter
|
|||||||
{
|
{
|
||||||
if (File.Exists(cacheFilePath))
|
if (File.Exists(cacheFilePath))
|
||||||
{
|
{
|
||||||
string remoteMd5 = await Digest.GetFileMD5Async(cacheFilePath).ConfigureAwait(false);
|
string remoteMd5 = await MD5.HashFileAsync(cacheFilePath).ConfigureAwait(false);
|
||||||
if (info.Md5 == remoteMd5.ToLowerInvariant() && new FileInfo(cacheFilePath).Length == info.TotalBytes)
|
if (info.Md5 == remoteMd5.ToLowerInvariant() && new FileInfo(cacheFilePath).Length == info.TotalBytes)
|
||||||
{
|
{
|
||||||
// Valid, move it to target path
|
// Valid, move it to target path
|
||||||
@@ -270,7 +271,7 @@ internal sealed partial class PackageConverter
|
|||||||
StreamCopyWorker<PackageReplaceStatus> streamCopyWorker = new(webStream, fileStream, bytesRead => new(info.Target, bytesRead, totalBytes));
|
StreamCopyWorker<PackageReplaceStatus> streamCopyWorker = new(webStream, fileStream, bytesRead => new(info.Target, bytesRead, totalBytes));
|
||||||
await streamCopyWorker.CopyAsync(progress).ConfigureAwait(false);
|
await streamCopyWorker.CopyAsync(progress).ConfigureAwait(false);
|
||||||
fileStream.Seek(0, SeekOrigin.Begin);
|
fileStream.Seek(0, SeekOrigin.Begin);
|
||||||
string remoteMd5 = await Digest.GetStreamMD5Async(fileStream).ConfigureAwait(false);
|
string remoteMd5 = await MD5.HashAsync(fileStream).ConfigureAwait(false);
|
||||||
if (string.Equals(info.Md5, remoteMd5, StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(info.Md5, remoteMd5, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ internal static class ProcessInterop
|
|||||||
public static Task UnlockFpsAsync(IServiceProvider serviceProvider, Process game)
|
public static Task UnlockFpsAsync(IServiceProvider serviceProvider, Process game)
|
||||||
{
|
{
|
||||||
IGameFpsUnlocker unlocker = serviceProvider.CreateInstance<GameFpsUnlocker>(game);
|
IGameFpsUnlocker unlocker = serviceProvider.CreateInstance<GameFpsUnlocker>(game);
|
||||||
UnlockTimingOptions options = new(100, 10000, 3000);
|
UnlockTimingOptions options = new(100, 20000, 3000);
|
||||||
return unlocker.UnlockAsync(options);
|
return unlocker.UnlockAsync(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -90,14 +90,14 @@ internal interface IMetadataService : ICastableService
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="token">取消令牌</param>
|
/// <param name="token">取消令牌</param>
|
||||||
/// <returns>圣遗物强化属性列表</returns>
|
/// <returns>圣遗物强化属性列表</returns>
|
||||||
ValueTask<List<ReliquaryAffix>> GetReliquaryAffixesAsync(CancellationToken token = default);
|
ValueTask<List<ReliquarySubAffix>> GetReliquarySubAffixesAsync(CancellationToken token = default);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步获取圣遗物等级数据
|
/// 异步获取圣遗物等级数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="token">取消令牌</param>
|
/// <param name="token">取消令牌</param>
|
||||||
/// <returns>圣遗物等级数据</returns>
|
/// <returns>圣遗物等级数据</returns>
|
||||||
ValueTask<List<ReliquaryLevel>> GetReliquaryLevelsAsync(CancellationToken token = default);
|
ValueTask<List<ReliquaryMainAffixLevel>> GetReliquaryLevelsAsync(CancellationToken token = default);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步获取圣遗物主属性强化属性列表
|
/// 异步获取圣遗物主属性强化属性列表
|
||||||
@@ -156,7 +156,7 @@ internal interface IMetadataService : ICastableService
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="token">取消令牌</param>
|
/// <param name="token">取消令牌</param>
|
||||||
/// <returns>显示与材料映射</returns>
|
/// <returns>显示与材料映射</returns>
|
||||||
ValueTask<Dictionary<MaterialId, Display>> GetIdToDisplayAndMaterialMapAsync(CancellationToken token = default);
|
ValueTask<Dictionary<MaterialId, DisplayItem>> GetIdToDisplayAndMaterialMapAsync(CancellationToken token = default);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步获取Id到材料的字典
|
/// 异步获取Id到材料的字典
|
||||||
@@ -170,7 +170,7 @@ internal interface IMetadataService : ICastableService
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="token">取消令牌</param>
|
/// <param name="token">取消令牌</param>
|
||||||
/// <returns>字典</returns>
|
/// <returns>字典</returns>
|
||||||
ValueTask<Dictionary<ReliquaryAffixId, ReliquaryAffix>> GetIdToReliquaryAffixMapAsync(CancellationToken token = default);
|
ValueTask<Dictionary<ReliquarySubAffixId, ReliquarySubAffix>> GetIdToReliquarySubAffixMapAsync(CancellationToken token = default);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步获取圣遗物主词条Id与属性的字典
|
/// 异步获取圣遗物主词条Id与属性的字典
|
||||||
@@ -211,20 +211,20 @@ internal interface IMetadataService : ICastableService
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="token">取消令牌</param>
|
/// <param name="token">取消令牌</param>
|
||||||
/// <returns>等级角色曲线映射</returns>
|
/// <returns>等级角色曲线映射</returns>
|
||||||
ValueTask<Dictionary<int, Dictionary<GrowCurveType, float>>> GetLevelToAvatarCurveMapAsync(CancellationToken token = default);
|
ValueTask<Dictionary<Level, Dictionary<GrowCurveType, float>>> GetLevelToAvatarCurveMapAsync(CancellationToken token = default);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步获取等级怪物曲线映射
|
/// 异步获取等级怪物曲线映射
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="token">取消令牌</param>
|
/// <param name="token">取消令牌</param>
|
||||||
/// <returns>等级怪物曲线映射</returns>
|
/// <returns>等级怪物曲线映射</returns>
|
||||||
ValueTask<Dictionary<int, Dictionary<GrowCurveType, float>>> GetLevelToMonsterCurveMapAsync(CancellationToken token = default);
|
ValueTask<Dictionary<Level, Dictionary<GrowCurveType, float>>> GetLevelToMonsterCurveMapAsync(CancellationToken token = default);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 异步获取等级武器曲线映射
|
/// 异步获取等级武器曲线映射
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="token">取消令牌</param>
|
/// <param name="token">取消令牌</param>
|
||||||
/// <returns>等级武器曲线映射</returns>
|
/// <returns>等级武器曲线映射</returns>
|
||||||
ValueTask<Dictionary<int, Dictionary<GrowCurveType, float>>> GetLevelToWeaponCurveMapAsync(CancellationToken token = default);
|
ValueTask<Dictionary<Level, Dictionary<GrowCurveType, float>>> GetLevelToWeaponCurveMapAsync(CancellationToken token = default);
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
@@ -84,7 +84,7 @@ internal sealed partial class MetadataOptions : IOptions<MetadataOptions>
|
|||||||
/// <returns>服务器上的本地化元数据文件</returns>
|
/// <returns>服务器上的本地化元数据文件</returns>
|
||||||
public string GetLocalizedRemoteFile(string fileNameWithExtension)
|
public string GetLocalizedRemoteFile(string fileNameWithExtension)
|
||||||
{
|
{
|
||||||
return Web.HutaoEndpoints.HutaoMetadataFile(LocaleName, fileNameWithExtension);
|
return Web.HutaoEndpoints.RawGithubUserContentMetadataFile(LocaleName, fileNameWithExtension);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetLocaleName()
|
private string GetLocaleName()
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Service.Metadata;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 名称常量
|
||||||
|
/// </summary>
|
||||||
|
internal partial class MetadataService
|
||||||
|
{
|
||||||
|
private const string FileNameAchievement = "Achievement";
|
||||||
|
private const string FileNameAchievementGoal = "AchievementGoal";
|
||||||
|
private const string FileNameAvatar = "Avatar";
|
||||||
|
private const string FileNameAvatarCurve = "AvatarCurve";
|
||||||
|
private const string FileNameAvatarPromote = "AvatarPromote";
|
||||||
|
private const string FileNameDisplayItem = "DisplayItem";
|
||||||
|
private const string FileNameGachaEvent = "GachaEvent";
|
||||||
|
private const string FileNameMaterial = "Material";
|
||||||
|
private const string FileNameMonster = "Monster";
|
||||||
|
private const string FileNameMonsterCurve = "MonsterCurve";
|
||||||
|
private const string FileNameReliquary = "Reliquary";
|
||||||
|
private const string FileNameReliquaryAffixWeight = "ReliquaryAffixWeight";
|
||||||
|
private const string FileNameReliquaryMainAffix = "ReliquaryMainAffix";
|
||||||
|
private const string FileNameReliquaryMainAffixLevel = "ReliquaryMainAffixLevel";
|
||||||
|
private const string FileNameReliquarySet = "ReliquarySet";
|
||||||
|
private const string FileNameReliquarySubAffix = "ReliquarySubAffix";
|
||||||
|
private const string FileNameTowerFloor = "TowerFloor";
|
||||||
|
private const string FileNameTowerLevel = "TowerLevel";
|
||||||
|
private const string FileNameTowerSchedule = "TowerSchedule";
|
||||||
|
private const string FileNameWeapon = "Weapon";
|
||||||
|
private const string FileNameWeaponCurve = "WeaponCurve";
|
||||||
|
private const string FileNameWeaponPromote = "WeaponPromote";
|
||||||
|
}
|
||||||
@@ -19,84 +19,84 @@ internal sealed partial class MetadataService
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ValueTask<List<AchievementGoal>> GetAchievementGoalsAsync(CancellationToken token = default)
|
public ValueTask<List<AchievementGoal>> GetAchievementGoalsAsync(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
return FromCacheOrFileAsync<List<AchievementGoal>>("AchievementGoal", token);
|
return FromCacheOrFileAsync<List<AchievementGoal>>(FileNameAchievementGoal, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ValueTask<List<Model.Metadata.Achievement.Achievement>> GetAchievementsAsync(CancellationToken token = default)
|
public ValueTask<List<Model.Metadata.Achievement.Achievement>> GetAchievementsAsync(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
return FromCacheOrFileAsync<List<Model.Metadata.Achievement.Achievement>>("Achievement", token);
|
return FromCacheOrFileAsync<List<Model.Metadata.Achievement.Achievement>>(FileNameAchievement, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ValueTask<List<Avatar>> GetAvatarsAsync(CancellationToken token = default)
|
public ValueTask<List<Avatar>> GetAvatarsAsync(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
return FromCacheOrFileAsync<List<Avatar>>("Avatar", token);
|
return FromCacheOrFileAsync<List<Avatar>>(FileNameAvatar, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ValueTask<List<Promote>> GetAvatarPromotesAsync(CancellationToken token = default)
|
public ValueTask<List<Promote>> GetAvatarPromotesAsync(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
return FromCacheOrFileAsync<List<Promote>>("AvatarPromote", token);
|
return FromCacheOrFileAsync<List<Promote>>(FileNameAvatarPromote, token);
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public ValueTask<List<Promote>> GetWeaponPromotesAsync(CancellationToken token = default)
|
|
||||||
{
|
|
||||||
return FromCacheOrFileAsync<List<Promote>>("WeaponPromote", token);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ValueTask<List<GachaEvent>> GetGachaEventsAsync(CancellationToken token = default)
|
public ValueTask<List<GachaEvent>> GetGachaEventsAsync(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
return FromCacheOrFileAsync<List<GachaEvent>>("GachaEvent2", token);
|
return FromCacheOrFileAsync<List<GachaEvent>>(FileNameGachaEvent, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ValueTask<List<Material>> GetMaterialsAsync(CancellationToken token = default)
|
public ValueTask<List<Material>> GetMaterialsAsync(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
return FromCacheOrFileAsync<List<Material>>("Material", token);
|
return FromCacheOrFileAsync<List<Material>>(FileNameMaterial, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ValueTask<List<Monster>> GetMonstersAsync(CancellationToken token = default)
|
public ValueTask<List<Monster>> GetMonstersAsync(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
return FromCacheOrFileAsync<List<Monster>>("Monster", token);
|
return FromCacheOrFileAsync<List<Monster>>(FileNameMonster, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ValueTask<List<Reliquary>> GetReliquariesAsync(CancellationToken token = default)
|
public ValueTask<List<Reliquary>> GetReliquariesAsync(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
return FromCacheOrFileAsync<List<Reliquary>>("Reliquary", token);
|
return FromCacheOrFileAsync<List<Reliquary>>(FileNameReliquary, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ValueTask<List<ReliquaryAffix>> GetReliquaryAffixesAsync(CancellationToken token = default)
|
public ValueTask<List<ReliquaryMainAffixLevel>> GetReliquaryLevelsAsync(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
return FromCacheOrFileAsync<List<ReliquaryAffix>>("ReliquaryAffix", token);
|
return FromCacheOrFileAsync<List<ReliquaryMainAffixLevel>>(FileNameReliquaryMainAffixLevel, token);
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public ValueTask<List<ReliquaryLevel>> GetReliquaryLevelsAsync(CancellationToken token = default)
|
|
||||||
{
|
|
||||||
return FromCacheOrFileAsync<List<ReliquaryLevel>>("ReliquaryMainAffixLevel", token);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ValueTask<List<ReliquaryMainAffix>> GetReliquaryMainAffixesAsync(CancellationToken token = default)
|
public ValueTask<List<ReliquaryMainAffix>> GetReliquaryMainAffixesAsync(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
return FromCacheOrFileAsync<List<ReliquaryMainAffix>>("ReliquaryMainAffix", token);
|
return FromCacheOrFileAsync<List<ReliquaryMainAffix>>(FileNameReliquaryMainAffix, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ValueTask<List<ReliquarySet>> GetReliquarySetsAsync(CancellationToken token = default)
|
public ValueTask<List<ReliquarySet>> GetReliquarySetsAsync(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
return FromCacheOrFileAsync<List<ReliquarySet>>("ReliquarySet", token);
|
return FromCacheOrFileAsync<List<ReliquarySet>>(FileNameReliquarySet, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public ValueTask<List<ReliquarySubAffix>> GetReliquarySubAffixesAsync(CancellationToken token = default)
|
||||||
|
{
|
||||||
|
return FromCacheOrFileAsync<List<ReliquarySubAffix>>(FileNameReliquarySubAffix, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ValueTask<List<Weapon>> GetWeaponsAsync(CancellationToken token = default)
|
public ValueTask<List<Weapon>> GetWeaponsAsync(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
return FromCacheOrFileAsync<List<Weapon>>("Weapon", token);
|
return FromCacheOrFileAsync<List<Weapon>>(FileNameWeapon, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public ValueTask<List<Promote>> GetWeaponPromotesAsync(CancellationToken token = default)
|
||||||
|
{
|
||||||
|
return FromCacheOrFileAsync<List<Promote>>(FileNameWeaponPromote, token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ using Snap.Hutao.Model.Metadata.Item;
|
|||||||
using Snap.Hutao.Model.Metadata.Reliquary;
|
using Snap.Hutao.Model.Metadata.Reliquary;
|
||||||
using Snap.Hutao.Model.Metadata.Weapon;
|
using Snap.Hutao.Model.Metadata.Weapon;
|
||||||
using Snap.Hutao.Model.Primitive;
|
using Snap.Hutao.Model.Primitive;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace Snap.Hutao.Service.Metadata;
|
namespace Snap.Hutao.Service.Metadata;
|
||||||
|
|
||||||
@@ -20,38 +21,38 @@ internal sealed partial class MetadataService
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ValueTask<Dictionary<EquipAffixId, ReliquarySet>> GetEquipAffixIdToReliquarySetMapAsync(CancellationToken token = default)
|
public ValueTask<Dictionary<EquipAffixId, ReliquarySet>> GetEquipAffixIdToReliquarySetMapAsync(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
return FromCacheAsDictionaryAsync<EquipAffixId, ReliquarySet>("ReliquarySet", r => r.EquipAffixId, token);
|
return FromCacheAsDictionaryAsync<EquipAffixId, ReliquarySet>(FileNameReliquarySet, r => r.EquipAffixId, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ValueTask<Dictionary<AchievementId, Model.Metadata.Achievement.Achievement>> GetIdToAchievementMapAsync(CancellationToken token = default)
|
public ValueTask<Dictionary<AchievementId, Model.Metadata.Achievement.Achievement>> GetIdToAchievementMapAsync(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
return FromCacheAsDictionaryAsync<AchievementId, Model.Metadata.Achievement.Achievement>("Achievement", a => a.Id, token);
|
return FromCacheAsDictionaryAsync<AchievementId, Model.Metadata.Achievement.Achievement>(FileNameAchievement, a => a.Id, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ValueTask<Dictionary<AvatarId, Avatar>> GetIdToAvatarMapAsync(CancellationToken token = default)
|
public ValueTask<Dictionary<AvatarId, Avatar>> GetIdToAvatarMapAsync(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
return FromCacheAsDictionaryAsync<AvatarId, Avatar>("Avatar", a => a.Id, token);
|
return FromCacheAsDictionaryAsync<AvatarId, Avatar>(FileNameAvatar, a => a.Id, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async ValueTask<Dictionary<MaterialId, Display>> GetIdToDisplayAndMaterialMapAsync(CancellationToken token = default)
|
public async ValueTask<Dictionary<MaterialId, DisplayItem>> GetIdToDisplayAndMaterialMapAsync(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
string cacheKey = $"{nameof(MetadataService)}.Cache.DisplayAndMaterial.Map.{typeof(MaterialId).Name}";
|
string cacheKey = $"{nameof(MetadataService)}.Cache.DisplayAndMaterial.Map.{typeof(MaterialId).Name}";
|
||||||
|
|
||||||
if (memoryCache.TryGetValue(cacheKey, out object? value))
|
if (memoryCache.TryGetValue(cacheKey, out object? value))
|
||||||
{
|
{
|
||||||
return Must.NotNull((Dictionary<MaterialId, Display>)value!);
|
return Must.NotNull((Dictionary<MaterialId, DisplayItem>)value!);
|
||||||
}
|
}
|
||||||
|
|
||||||
Dictionary<MaterialId, Display> displays = await FromCacheAsDictionaryAsync<MaterialId, Display>("Display", a => a.Id, token).ConfigureAwait(false);
|
Dictionary<MaterialId, DisplayItem> displays = await FromCacheAsDictionaryAsync<MaterialId, DisplayItem>(FileNameDisplayItem, a => a.Id, token).ConfigureAwait(false);
|
||||||
Dictionary<MaterialId, Material> materials = await GetIdToMaterialMapAsync(token).ConfigureAwait(false);
|
Dictionary<MaterialId, Material> materials = await GetIdToMaterialMapAsync(token).ConfigureAwait(false);
|
||||||
|
|
||||||
// TODO: Cache this
|
// TODO: Cache this
|
||||||
Dictionary<MaterialId, Display> results = new(displays);
|
Dictionary<MaterialId, DisplayItem> results = new(displays);
|
||||||
|
|
||||||
foreach ((MaterialId id, Display material) in materials)
|
foreach ((MaterialId id, DisplayItem material) in materials)
|
||||||
{
|
{
|
||||||
results[id] = material;
|
results[id] = material;
|
||||||
}
|
}
|
||||||
@@ -62,54 +63,54 @@ internal sealed partial class MetadataService
|
|||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ValueTask<Dictionary<MaterialId, Material>> GetIdToMaterialMapAsync(CancellationToken token = default)
|
public ValueTask<Dictionary<MaterialId, Material>> GetIdToMaterialMapAsync(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
return FromCacheAsDictionaryAsync<MaterialId, Material>("Material", a => a.Id, token);
|
return FromCacheAsDictionaryAsync<MaterialId, Material>(FileNameMaterial, a => a.Id, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ValueTask<Dictionary<ReliquaryAffixId, ReliquaryAffix>> GetIdToReliquaryAffixMapAsync(CancellationToken token = default)
|
public ValueTask<Dictionary<ReliquarySubAffixId, ReliquarySubAffix>> GetIdToReliquarySubAffixMapAsync(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
return FromCacheAsDictionaryAsync<ReliquaryAffixId, ReliquaryAffix>("ReliquaryAffix", a => a.Id, token);
|
return FromCacheAsDictionaryAsync<ReliquarySubAffixId, ReliquarySubAffix>(FileNameReliquarySubAffix, a => a.Id, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ValueTask<Dictionary<ReliquaryMainAffixId, FightProperty>> GetIdToReliquaryMainPropertyMapAsync(CancellationToken token = default)
|
public ValueTask<Dictionary<ReliquaryMainAffixId, FightProperty>> GetIdToReliquaryMainPropertyMapAsync(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
return FromCacheAsDictionaryAsync<ReliquaryMainAffixId, FightProperty, ReliquaryMainAffix>("ReliquaryMainAffix", r => r.Id, r => r.Type, token);
|
return FromCacheAsDictionaryAsync<ReliquaryMainAffixId, FightProperty, ReliquaryMainAffix>(FileNameReliquaryMainAffix, r => r.Id, r => r.Type, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ValueTask<Dictionary<WeaponId, Weapon>> GetIdToWeaponMapAsync(CancellationToken token = default)
|
public ValueTask<Dictionary<WeaponId, Weapon>> GetIdToWeaponMapAsync(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
return FromCacheAsDictionaryAsync<WeaponId, Weapon>("Weapon", w => w.Id, token);
|
return FromCacheAsDictionaryAsync<WeaponId, Weapon>(FileNameWeapon, w => w.Id, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ValueTask<Dictionary<int, Dictionary<GrowCurveType, float>>> GetLevelToAvatarCurveMapAsync(CancellationToken token = default)
|
public ValueTask<Dictionary<Level, Dictionary<GrowCurveType, float>>> GetLevelToAvatarCurveMapAsync(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
return FromCacheAsDictionaryAsync<int, Dictionary<GrowCurveType, float>, GrowCurve>("AvatarCurve", a => a.Level, a => a.Curves, token);
|
return FromCacheAsDictionaryAsync<Level, Dictionary<GrowCurveType, float>, GrowCurve>(FileNameAvatarCurve, a => a.Level, a => a.CurveMap, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ValueTask<Dictionary<int, Dictionary<GrowCurveType, float>>> GetLevelToMonsterCurveMapAsync(CancellationToken token = default)
|
public ValueTask<Dictionary<Level, Dictionary<GrowCurveType, float>>> GetLevelToMonsterCurveMapAsync(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
return FromCacheAsDictionaryAsync<int, Dictionary<GrowCurveType, float>, GrowCurve>("MonsterCurve", m => m.Level, m => m.Curves, token);
|
return FromCacheAsDictionaryAsync<Level, Dictionary<GrowCurveType, float>, GrowCurve>(FileNameMonsterCurve, m => m.Level, m => m.CurveMap, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ValueTask<Dictionary<int, Dictionary<GrowCurveType, float>>> GetLevelToWeaponCurveMapAsync(CancellationToken token = default)
|
public ValueTask<Dictionary<Level, Dictionary<GrowCurveType, float>>> GetLevelToWeaponCurveMapAsync(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
return FromCacheAsDictionaryAsync<int, Dictionary<GrowCurveType, float>, GrowCurve>("WeaponCurve", w => w.Level, w => w.Curves, token);
|
return FromCacheAsDictionaryAsync<Level, Dictionary<GrowCurveType, float>, GrowCurve>(FileNameWeaponCurve, w => w.Level, w => w.CurveMap, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ValueTask<Dictionary<string, Avatar>> GetNameToAvatarMapAsync(CancellationToken token = default)
|
public ValueTask<Dictionary<string, Avatar>> GetNameToAvatarMapAsync(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
return FromCacheAsDictionaryAsync<string, Avatar>("Avatar", a => a.Name, token);
|
return FromCacheAsDictionaryAsync<string, Avatar>(FileNameAvatar, a => a.Name, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ValueTask<Dictionary<string, Weapon>> GetNameToWeaponMapAsync(CancellationToken token = default)
|
public ValueTask<Dictionary<string, Weapon>> GetNameToWeaponMapAsync(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
return FromCacheAsDictionaryAsync<string, Weapon>("Weapon", w => w.Name, token);
|
return FromCacheAsDictionaryAsync<string, Weapon>(FileNameWeapon, w => w.Name, token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,7 +6,7 @@ using Snap.Hutao.Core;
|
|||||||
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
|
using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient;
|
||||||
using Snap.Hutao.Core.Diagnostics;
|
using Snap.Hutao.Core.Diagnostics;
|
||||||
using Snap.Hutao.Core.ExceptionService;
|
using Snap.Hutao.Core.ExceptionService;
|
||||||
using Snap.Hutao.Core.IO;
|
using Snap.Hutao.Core.IO.Hashing;
|
||||||
using Snap.Hutao.Service.Notification;
|
using Snap.Hutao.Service.Notification;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
@@ -122,12 +122,12 @@ internal sealed partial class MetadataService : IMetadataService, IMetadataServi
|
|||||||
string fileFullPath = metadataOptions.GetLocalizedLocalFile(fileFullName);
|
string fileFullPath = metadataOptions.GetLocalizedLocalFile(fileFullName);
|
||||||
if (File.Exists(fileFullPath))
|
if (File.Exists(fileFullPath))
|
||||||
{
|
{
|
||||||
skip = md5 == await Digest.GetFileMD5Async(fileFullPath, token).ConfigureAwait(false);
|
skip = md5 == await XXH64.HashFileAsync(fileFullPath, token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!skip)
|
if (!skip)
|
||||||
{
|
{
|
||||||
logger.LogInformation("MD5 of {file} not matched, begin downloading", fileFullName);
|
logger.LogInformation("{hash} of {file} not matched, begin downloading", nameof(XXH64), fileFullName);
|
||||||
|
|
||||||
await DownloadMetadataAsync(fileFullName, token).ConfigureAwait(false);
|
await DownloadMetadataAsync(fileFullName, token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@@ -182,6 +182,7 @@ internal sealed partial class MetadataService : IMetadataService, IMetadataServi
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
FileNotFoundException exception = new(SH.ServiceMetadataFileNotFound, fileName);
|
||||||
throw ThrowHelper.UserdataCorrupted(SH.ServiceMetadataFileNotFound, null!);
|
throw ThrowHelper.UserdataCorrupted(SH.ServiceMetadataFileNotFound, null!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -253,7 +253,7 @@
|
|||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="7.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="7.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" />
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.5.22">
|
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.6.40">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
@@ -268,6 +268,7 @@
|
|||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
<PackageReference Include="System.IO.Hashing" Version="7.0.0" />
|
||||||
<PackageReference Include="TaskScheduler" Version="2.10.1" />
|
<PackageReference Include="TaskScheduler" Version="2.10.1" />
|
||||||
<Manifest Include="$(ApplicationManifest)" />
|
<Manifest Include="$(ApplicationManifest)" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ namespace Snap.Hutao.View.Control;
|
|||||||
[HighQuality]
|
[HighQuality]
|
||||||
internal sealed partial class ItemIcon : UserControl
|
internal sealed partial class ItemIcon : UserControl
|
||||||
{
|
{
|
||||||
private static readonly DependencyProperty QualityProperty = Property<ItemIcon>.Depend(nameof(Quality), ItemQuality.QUALITY_NONE);
|
private static readonly DependencyProperty QualityProperty = Property<ItemIcon>.Depend(nameof(Quality), QualityType.QUALITY_NONE);
|
||||||
private static readonly DependencyProperty IconProperty = Property<ItemIcon>.Depend<Uri>(nameof(Icon));
|
private static readonly DependencyProperty IconProperty = Property<ItemIcon>.Depend<Uri>(nameof(Icon));
|
||||||
private static readonly DependencyProperty BadgeProperty = Property<ItemIcon>.Depend<Uri>(nameof(Badge));
|
private static readonly DependencyProperty BadgeProperty = Property<ItemIcon>.Depend<Uri>(nameof(Badge));
|
||||||
|
|
||||||
@@ -29,9 +29,9 @@ internal sealed partial class ItemIcon : UserControl
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 等阶
|
/// 等阶
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ItemQuality Quality
|
public QualityType Quality
|
||||||
{
|
{
|
||||||
get => (ItemQuality)GetValue(QualityProperty);
|
get => (QualityType)GetValue(QualityProperty);
|
||||||
set => SetValue(QualityProperty, value);
|
set => SetValue(QualityProperty, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -521,7 +521,7 @@
|
|||||||
Width="80"
|
Width="80"
|
||||||
Height="80"
|
Height="80"
|
||||||
Margin="0,0,16,0"
|
Margin="0,0,16,0"
|
||||||
Source="{Binding Icon, Converter={StaticResource AvatarCardConverter}}"/>
|
Source="{Binding FrontIcon, Converter={StaticResource AvatarCardConverter}}"/>
|
||||||
<StackPanel Grid.Column="1" Margin="0,0,16,-4">
|
<StackPanel Grid.Column="1" Margin="0,0,16,-4">
|
||||||
<TextBlock Text="{Binding Name}"/>
|
<TextBlock Text="{Binding Name}"/>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ internal sealed class AchievementGoalView : ObservableObject, INameIcon
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 排序顺序
|
/// 排序顺序
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Order { get; }
|
public uint Order { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 名称
|
/// 名称
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ internal sealed class AvatarView : INameIconSide, ICalculableSource<ICalculableA
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 星级
|
/// 星级
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ItemQuality Quality { get; set; }
|
public QualityType Quality { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 元素类型
|
/// 元素类型
|
||||||
@@ -91,7 +91,7 @@ internal sealed class AvatarView : INameIconSide, ICalculableSource<ICalculableA
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 好感度等级
|
/// 好感度等级
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int FetterLevel { get; set; }
|
public uint FetterLevel { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Id
|
/// Id
|
||||||
@@ -101,7 +101,7 @@ internal sealed class AvatarView : INameIconSide, ICalculableSource<ICalculableA
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 等级数字
|
/// 等级数字
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal int LevelNumber { get; set; }
|
internal uint LevelNumber { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ICalculableAvatar ToCalculable()
|
public ICalculableAvatar ToCalculable()
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ internal abstract class Equip : NameIconDescription
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 品质
|
/// 品质
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ItemQuality Quality { get; set; }
|
public QualityType Quality { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 主属性
|
/// 主属性
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using Snap.Hutao.Model.Calculable;
|
using Snap.Hutao.Model.Calculable;
|
||||||
using Snap.Hutao.Model.Metadata;
|
using Snap.Hutao.Model.Metadata;
|
||||||
|
using Snap.Hutao.Model.Primitive;
|
||||||
|
|
||||||
namespace Snap.Hutao.ViewModel.AvatarProperty;
|
namespace Snap.Hutao.ViewModel.AvatarProperty;
|
||||||
|
|
||||||
@@ -20,7 +21,7 @@ internal sealed class SkillView : NameIconDescription, ICalculableSource<ICalcul
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 不计算命座的技能等级
|
/// 不计算命座的技能等级
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int LevelNumber { get; set; }
|
public uint LevelNumber { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 不计算命座的技能等级字符串
|
/// 不计算命座的技能等级字符串
|
||||||
@@ -30,7 +31,7 @@ internal sealed class SkillView : NameIconDescription, ICalculableSource<ICalcul
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 技能组Id
|
/// 技能组Id
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal int GroupId { get; set; }
|
internal SkillGroupId GroupId { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ICalculableSkill ToCalculable()
|
public ICalculableSkill ToCalculable()
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ internal sealed class WeaponView : Equip, ICalculableSource<ICalculableWeapon>
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 精炼等级
|
/// 精炼等级
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int AffixLevelNumber { get; set; }
|
public uint AffixLevelNumber { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 精炼属性
|
/// 精炼属性
|
||||||
@@ -45,12 +45,12 @@ internal sealed class WeaponView : Equip, ICalculableSource<ICalculableWeapon>
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 等级数字
|
/// 等级数字
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal int LevelNumber { get; set; }
|
internal uint LevelNumber { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 最大等级
|
/// 最大等级
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal int MaxLevel { get => ((int)Quality) >= 3 ? 90 : 70; }
|
internal uint MaxLevel { get => ((int)Quality) >= 3 ? 90U : 70U; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ICalculableWeapon ToCalculable()
|
public ICalculableWeapon ToCalculable()
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ internal class AvatarView : INameIconSide
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 星级
|
/// 星级
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ItemQuality Quality { get; }
|
public QualityType Quality { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 比率
|
/// 比率
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user