diff --git a/src/Snap.Hutao/Snap.Hutao.SourceGeneration/Identity/IdentityGenerator.cs b/src/Snap.Hutao/Snap.Hutao.SourceGeneration/Identity/IdentityGenerator.cs index 3447bb91..26de90b7 100644 --- a/src/Snap.Hutao/Snap.Hutao.SourceGeneration/Identity/IdentityGenerator.cs +++ b/src/Snap.Hutao/Snap.Hutao.SourceGeneration/Identity/IdentityGenerator.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.IO; using System.Linq; +using System.Text; namespace Snap.Hutao.SourceGeneration.Identity; @@ -32,8 +33,6 @@ internal sealed class IdentityGenerator : IIncrementalGenerator if (identities.Any()) { - GenerateIdentityConverter(context); - foreach (IdentityStructMetadata identityStruct in identities) { 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 = $$""" - // Copyright (c) DGP Studio. All rights reserved. - // Licensed under the MIT license. + string name = metadata.Name; - namespace Snap.Hutao.Model.Primitive.Converter; - - /// - /// Id 转换器 - /// - /// 包装类型 - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("{{nameof(IdentityGenerator)}}", "1.0.0.0")] - internal unsafe sealed class IdentityConverter : JsonConverter - where TWrapper : unmanaged - { - /// - 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(); - } - - /// - 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 = $$""" + StringBuilder sourceBuilder = new StringBuilder().AppendLine($$""" // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. using Snap.Hutao.Model.Primitive.Converter; + using System.Numerics; namespace Snap.Hutao.Model.Primitive; /// - /// {{identityStruct.Documentation}} + /// {{metadata.Documentation}} /// [JsonConverter(typeof(IdentityConverter<{{name}}>))] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("{{nameof(IdentityGenerator)}}","1.0.0.0")] - internal readonly struct {{name}} : IEquatable<{{name}}> + internal readonly partial struct {{name}} { /// /// 值 /// - public readonly {{type}} Value; + public readonly uint Value; /// /// Initializes a new instance of the struct. /// /// value - public {{name}}({{type}} value) + public {{name}}(uint value) { Value = value; } - public static implicit operator {{type}}({{name}} value) + public static implicit operator uint({{name}} value) { return value.Value; } - public static implicit operator {{name}}({{type}} value) + public static implicit operator {{name}}(uint 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); - } - - /// - public bool Equals({{name}} other) - { - return Value == other.Value; - } - - /// - public override bool Equals(object obj) - { - return obj is {{name}} other && Equals(other); - } - /// public override int GetHashCode() { return Value.GetHashCode(); } } - """; + """); - context.AddSource($"{name}.g.cs", source); + if (metadata.Equatable) + { + sourceBuilder.AppendLine($$""" + + internal readonly partial struct {{name}} : IEquatable<{{name}}> + { + /// + public override bool Equals(object obj) + { + return obj is {{name}} other && Equals(other); + } + + /// + 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 { - /// - /// 名称 - /// public string Name { get; set; } = default!; - /// - /// 基底类型 - /// - public string Type { get; set; } = default!; - - /// - /// 文档 - /// 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; } } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao.Test/JsonSerializeTest.cs b/src/Snap.Hutao/Snap.Hutao.Test/JsonSerializeTest.cs index 40724e6b..718408d1 100644 --- a/src/Snap.Hutao/Snap.Hutao.Test/JsonSerializeTest.cs +++ b/src/Snap.Hutao/Snap.Hutao.Test/JsonSerializeTest.cs @@ -1,4 +1,5 @@ -using System.Text.Json; +using System.Collections.Generic; +using System.Text.Json; using System.Text.Json.Serialization; namespace Snap.Hutao.Test; @@ -18,6 +19,13 @@ public class JsonSerializeTest } """; + private const string SmapleNumberDictionaryJson = """ + { + "111" : "12", + "222" : "34" + } + """; + [TestMethod] public void DelegatePropertyCanSerialize() { @@ -26,11 +34,33 @@ public class JsonSerializeTest } [TestMethod] - public void EmptyStringCanSerializeAsNumber() + public void EmptyStringCannotSerializeAsNumber() { - // Throw - StringNumberSample sample = JsonSerializer.Deserialize(SmapleNumberObjectJson)!; - Assert.AreEqual(sample.A, 0); + bool caught = false; + try + { + // Throw + StringNumberSample sample = JsonSerializer.Deserialize(SmapleNumberObjectJson)!; + Assert.AreEqual(sample.A, 0); + } + catch + { + caught = true; + } + + Assert.IsTrue(caught); + } + + [TestMethod] + public void NumberStringKeyCanSerializeAsKey() + { + JsonSerializerOptions options = new() + { + NumberHandling = JsonNumberHandling.AllowReadingFromString, + }; + + Dictionary sample = JsonSerializer.Deserialize>(SmapleNumberDictionaryJson, options)!; + Assert.AreEqual(sample[111], "12"); } private class Sample diff --git a/src/Snap.Hutao/Snap.Hutao/Core/ExceptionService/UserdataCorruptedException.cs b/src/Snap.Hutao/Snap.Hutao/Core/ExceptionService/UserdataCorruptedException.cs index d0e18b58..dae43281 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/ExceptionService/UserdataCorruptedException.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/ExceptionService/UserdataCorruptedException.cs @@ -14,8 +14,8 @@ internal sealed class UserdataCorruptedException : Exception /// /// 消息 /// 内部错误 - public UserdataCorruptedException(string message, Exception innerException) - : base(string.Format(SH.CoreExceptionServiceUserdataCorruptedMessage, $"{message}\n{innerException.Message}"), innerException) + public UserdataCorruptedException(string message, Exception? innerException) + : base(string.Format(SH.CoreExceptionServiceUserdataCorruptedMessage, $"{message}\n{innerException?.Message}"), innerException) { } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/IO/Digest.cs b/src/Snap.Hutao/Snap.Hutao/Core/IO/Hashing/MD5.cs similarity index 60% rename from src/Snap.Hutao/Snap.Hutao/Core/IO/Digest.cs rename to src/Snap.Hutao/Snap.Hutao/Core/IO/Hashing/MD5.cs index 1cb59b3a..2d05ee09 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/IO/Digest.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/IO/Hashing/MD5.cs @@ -2,39 +2,38 @@ // Licensed under the MIT license. using System.IO; -using System.Security.Cryptography; -namespace Snap.Hutao.Core.IO; +namespace Snap.Hutao.Core.IO.Hashing; /// /// 摘要 /// [HighQuality] -internal static class Digest +internal static class MD5 { /// - /// 异步获取文件 Md5 摘要 + /// 异步获取文件 MD5 摘要 /// /// 文件路径 /// 取消令牌 /// 文件 Md5 摘要 - public static async Task GetFileMD5Async(string filePath, CancellationToken token = default) + public static async Task HashFileAsync(string filePath, CancellationToken token = default) { using (FileStream stream = File.OpenRead(filePath)) { - return await GetStreamMD5Async(stream, token).ConfigureAwait(false); + return await HashAsync(stream, token).ConfigureAwait(false); } } /// - /// 获取流的 Md5 摘要 + /// 获取流的 MD5 摘要 /// /// 流 /// 取消令牌 /// 流 Md5 摘要 - public static async Task GetStreamMD5Async(Stream stream, CancellationToken token = default) + public static async Task 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); return System.Convert.ToHexString(bytes); diff --git a/src/Snap.Hutao/Snap.Hutao/Core/IO/Hashing/XXH64.cs b/src/Snap.Hutao/Snap.Hutao/Core/IO/Hashing/XXH64.cs new file mode 100644 index 00000000..3a980e26 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Core/IO/Hashing/XXH64.cs @@ -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; + +/// +/// XXH64 摘要 +/// +internal static class XXH64 +{ + /// + /// 获取流的 XXH64 摘要 + /// + /// 流 + /// 取消令牌 + /// 摘要 + public static async Task 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); + } + + /// + /// 获取文件的 XXH64 摘要 + /// + /// 路径 + /// 取消令牌 + /// 摘要 + public static async Task HashFileAsync(string path, CancellationToken token = default) + { + using (FileStream stream = File.OpenRead(path)) + { + return await HashAsync(stream, token).ConfigureAwait(false); + } + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Json/JsonOptions.cs b/src/Snap.Hutao/Snap.Hutao/Core/Json/JsonOptions.cs index fe2e35ee..33c06adc 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Json/JsonOptions.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Json/JsonOptions.cs @@ -20,6 +20,7 @@ internal static class JsonOptions ReadCommentHandling = JsonCommentHandling.Skip, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, + NumberHandling = JsonNumberHandling.AllowReadingFromString, PropertyNameCaseInsensitive = true, WriteIndented = true, TypeInfoResolver = new DefaultJsonTypeInfoResolver() diff --git a/src/Snap.Hutao/Snap.Hutao/Extension/EnumerableExtension.Dictionary.cs b/src/Snap.Hutao/Snap.Hutao/Extension/EnumerableExtension.Dictionary.cs index be2988a0..419bc009 100644 --- a/src/Snap.Hutao/Snap.Hutao/Extension/EnumerableExtension.Dictionary.cs +++ b/src/Snap.Hutao/Snap.Hutao/Extension/EnumerableExtension.Dictionary.cs @@ -1,6 +1,7 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -15,10 +16,12 @@ internal static partial class EnumerableExtension /// 增加计数 /// /// 键类型 + /// 值类型 /// 字典 /// 键 - public static void Increase(this Dictionary dict, TKey key) + public static void IncreaseOne(this Dictionary dict, TKey key) where TKey : notnull + where TValue : struct, IIncrementOperators { ++CollectionsMarshal.GetValueRefOrAddDefault(dict, key, out _); } @@ -27,14 +30,16 @@ internal static partial class EnumerableExtension /// 增加计数 /// /// 键类型 + /// 值类型 /// 字典 /// 键 /// 增加的值 - public static void Increase(this Dictionary dict, TKey key, int value) + public static void IncreaseValue(this Dictionary dict, TKey key, TValue value) where TKey : notnull + where TValue : struct, IAdditionOperators { // 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; } @@ -42,13 +47,15 @@ internal static partial class EnumerableExtension /// 增加计数 /// /// 键类型 + /// 值类型 /// 字典 /// 键 /// 是否存在键值 - public static bool TryIncrease(this Dictionary dict, TKey key) + public static bool TryIncreaseOne(this Dictionary dict, TKey key) where TKey : notnull + where TValue : struct, IIncrementOperators { - ref int value = ref CollectionsMarshal.GetValueRefOrNullRef(dict, key); + ref TValue value = ref CollectionsMarshal.GetValueRefOrNullRef(dict, key); if (!Unsafe.IsNullRef(ref value)) { ++value; diff --git a/src/Snap.Hutao/Snap.Hutao/Extension/NumberExtension.cs b/src/Snap.Hutao/Snap.Hutao/Extension/NumberExtension.cs index 1d026191..268a24ba 100644 --- a/src/Snap.Hutao/Snap.Hutao/Extension/NumberExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Extension/NumberExtension.cs @@ -17,9 +17,9 @@ internal static class NumberExtension /// 给定的整数 /// 位数 [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 - return (int)(MathF.Log10(x) + 1); + return (uint)(MathF.Log10(x) + 1); } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/IdentityStructs.json b/src/Snap.Hutao/Snap.Hutao/IdentityStructs.json index e3a3baac..8d57f038 100644 --- a/src/Snap.Hutao/Snap.Hutao/IdentityStructs.json +++ b/src/Snap.Hutao/Snap.Hutao/IdentityStructs.json @@ -1,82 +1,166 @@ [ { "Name": "AchievementGoalId", - "Type": "int", - "Documentation": "1-2位 成就分类Id" + "Documentation": "成就分类 Id", + "Equatable": true, + "EqualityOperators": true }, { "Name": "AchievementId", - "Type": "int", - "Documentation": "5位 成就Id" + "Documentation": "成就 Id", + "Equatable": true, + "EqualityOperators": true }, { "Name": "AvatarId", - "Type": "int", - "Documentation": "8位 角色Id" + "Documentation": "角色 Id", + "Equatable": true, + "EqualityOperators": true }, { "Name": "CostumeId", - "Type": "int", - "Documentation": "6位 角色装扮Id" + "Documentation": "角色装扮 Id", + "Equatable": true, + "EqualityOperators": true }, { "Name": "EquipAffixId", - "Type": "int", - "Documentation": "6位 装备属性Id" + "Documentation": "装备属性 Id", + "Equatable": true, + "EqualityOperators": true }, { "Name": "ExtendedEquipAffixId", - "Type": "int", - "Documentation": "7位 装备属性Id" + "Documentation": "装备属性 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", - "Type": "int", - "Documentation": "3-6位 材料Id" + "Documentation": "材料 Id", + "Equatable": true, + "EqualityOperators": true + }, + { + "Name": "MonsterDescribeId", + "Documentation": "怪物描述 Id", + "Equatable": true, + "EqualityOperators": true }, { "Name": "MonsterId", - "Type": "int", - "Documentation": "8位 怪物Id" + "Documentation": "怪物 Id", + "Equatable": true, + "EqualityOperators": true }, { "Name": "PromoteId", - "Type": "int", - "Documentation": "1-5位 角色突破提升Id" + "Documentation": "角色突破提升 Id", + "Equatable": true, + "EqualityOperators": true }, { - "Name": "ReliquaryAffixId", - "Type": "int", - "Documentation": "6位 圣遗物副词条Id" + "Name": "PromoteLevel", + "Documentation": "突破等级 0 - 6", + "Equatable": true, + "EqualityOperators": true + }, + { + "Name": "ReliquaryLevel", + "Documentation": "圣遗物等级 1 - 21", + "Equatable": true, + "EqualityOperators": true + }, + { + "Name": "ReliquarySubAffixId", + "Documentation": "圣遗物副词条 Id", + "Equatable": true, + "EqualityOperators": true }, { "Name": "ReliquaryId", - "Type": "int", - "Documentation": "5位 圣遗物Id" + "Documentation": "圣遗物 Id", + "Equatable": true, + "EqualityOperators": true }, { "Name": "ReliquaryMainAffixId", - "Type": "int", - "Documentation": "5位 圣遗物主属性Id" + "Documentation": "圣遗物主属性 Id", + "Equatable": true, + "EqualityOperators": true }, { "Name": "ReliquarySetId", - "Type": "int", - "Documentation": "5位 圣遗物套装Id" + "Documentation": "圣遗物套装 Id", + "Equatable": true, + "EqualityOperators": true }, { "Name": "SkillGroupId", - "Type": "int", - "Documentation": "3-4位 技能组Id" + "Documentation": "技能组 Id", + "Equatable": true, + "EqualityOperators": true }, { "Name": "SkillId", - "Type": "int", - "Documentation": "5-6位 技能Id" + "Documentation": "技能 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", - "Type": "int", - "Documentation": "5位 武器Id" + "Documentation": "武器 Id", + "Equatable": true, + "EqualityOperators": true } ] \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Migrations/AppDbContextModelSnapshot.cs b/src/Snap.Hutao/Snap.Hutao/Migrations/AppDbContextModelSnapshot.cs index 82afbde1..0e896111 100644 --- a/src/Snap.Hutao/Snap.Hutao/Migrations/AppDbContextModelSnapshot.cs +++ b/src/Snap.Hutao/Snap.Hutao/Migrations/AppDbContextModelSnapshot.cs @@ -42,7 +42,7 @@ namespace Snap.Hutao.Migrations b.HasIndex("ArchiveId"); - b.ToTable("achievements"); + b.ToTable("achievements", (string)null); }); modelBuilder.Entity("Snap.Hutao.Model.Entity.AchievementArchive", b => @@ -60,7 +60,7 @@ namespace Snap.Hutao.Migrations b.HasKey("InnerId"); - b.ToTable("achievement_archives"); + b.ToTable("achievement_archives", (string)null); }); modelBuilder.Entity("Snap.Hutao.Model.Entity.AvatarInfo", b => @@ -79,7 +79,7 @@ namespace Snap.Hutao.Migrations b.HasKey("InnerId"); - b.ToTable("avatar_infos"); + b.ToTable("avatar_infos", (string)null); }); modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateEntry", b => @@ -101,7 +101,7 @@ namespace Snap.Hutao.Migrations b.HasIndex("ProjectId"); - b.ToTable("cultivate_entries"); + b.ToTable("cultivate_entries", (string)null); }); modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateItem", b => @@ -126,7 +126,7 @@ namespace Snap.Hutao.Migrations b.HasIndex("EntryId"); - b.ToTable("cultivate_items"); + b.ToTable("cultivate_items", (string)null); }); modelBuilder.Entity("Snap.Hutao.Model.Entity.CultivateProject", b => @@ -147,7 +147,7 @@ namespace Snap.Hutao.Migrations b.HasKey("InnerId"); - b.ToTable("cultivate_projects"); + b.ToTable("cultivate_projects", (string)null); }); modelBuilder.Entity("Snap.Hutao.Model.Entity.DailyNoteEntry", b => @@ -200,7 +200,7 @@ namespace Snap.Hutao.Migrations b.HasIndex("UserId"); - b.ToTable("daily_notes"); + b.ToTable("daily_notes", (string)null); }); modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaArchive", b => @@ -218,7 +218,7 @@ namespace Snap.Hutao.Migrations b.HasKey("InnerId"); - b.ToTable("gacha_archives"); + b.ToTable("gacha_archives", (string)null); }); modelBuilder.Entity("Snap.Hutao.Model.Entity.GachaItem", b => @@ -249,7 +249,7 @@ namespace Snap.Hutao.Migrations b.HasIndex("ArchiveId"); - b.ToTable("gacha_items"); + b.ToTable("gacha_items", (string)null); }); modelBuilder.Entity("Snap.Hutao.Model.Entity.GameAccount", b => @@ -274,7 +274,7 @@ namespace Snap.Hutao.Migrations b.HasKey("InnerId"); - b.ToTable("game_accounts"); + b.ToTable("game_accounts", (string)null); }); modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryItem", b => @@ -296,7 +296,7 @@ namespace Snap.Hutao.Migrations b.HasIndex("ProjectId"); - b.ToTable("inventory_items"); + b.ToTable("inventory_items", (string)null); }); modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryReliquary", b => @@ -325,7 +325,7 @@ namespace Snap.Hutao.Migrations b.HasIndex("ProjectId"); - b.ToTable("inventory_reliquaries"); + b.ToTable("inventory_reliquaries", (string)null); }); modelBuilder.Entity("Snap.Hutao.Model.Entity.InventoryWeapon", b => @@ -350,7 +350,7 @@ namespace Snap.Hutao.Migrations b.HasIndex("ProjectId"); - b.ToTable("inventory_weapons"); + b.ToTable("inventory_weapons", (string)null); }); modelBuilder.Entity("Snap.Hutao.Model.Entity.ObjectCacheEntry", b => @@ -366,7 +366,7 @@ namespace Snap.Hutao.Migrations b.HasKey("Key"); - b.ToTable("object_cache"); + b.ToTable("object_cache", (string)null); }); modelBuilder.Entity("Snap.Hutao.Model.Entity.SettingEntry", b => @@ -379,7 +379,7 @@ namespace Snap.Hutao.Migrations b.HasKey("Key"); - b.ToTable("settings"); + b.ToTable("settings", (string)null); }); modelBuilder.Entity("Snap.Hutao.Model.Entity.SpiralAbyssEntry", b => @@ -401,7 +401,7 @@ namespace Snap.Hutao.Migrations b.HasKey("InnerId"); - b.ToTable("spiral_abysses"); + b.ToTable("spiral_abysses", (string)null); }); modelBuilder.Entity("Snap.Hutao.Model.Entity.User", b => @@ -435,7 +435,7 @@ namespace Snap.Hutao.Migrations b.HasKey("InnerId"); - b.ToTable("users"); + b.ToTable("users", (string)null); }); modelBuilder.Entity("Snap.Hutao.Model.Entity.Achievement", b => diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Calculable/CalculableAvatar.cs b/src/Snap.Hutao/Snap.Hutao/Model/Calculable/CalculableAvatar.cs index 16444f23..cc44896c 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Calculable/CalculableAvatar.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Calculable/CalculableAvatar.cs @@ -15,8 +15,8 @@ namespace Snap.Hutao.Model.Calculable; [HighQuality] internal sealed class CalculableAvatar : ObservableObject, ICalculableAvatar { - private int levelCurrent; - private int levelTarget; + private uint levelCurrent; + private uint levelTarget; /// /// 构造一个新的可计算角色 @@ -58,10 +58,10 @@ internal sealed class CalculableAvatar : ObservableObject, ICalculableAvatar public AvatarId AvatarId { get; } /// - public int LevelMin { get; } + public uint LevelMin { get; } /// - public int LevelMax { get; } + public uint LevelMax { get; } /// public List Skills { get; } @@ -73,11 +73,11 @@ internal sealed class CalculableAvatar : ObservableObject, ICalculableAvatar public Uri Icon { get; } /// - public ItemQuality Quality { get; } + public QualityType Quality { get; } /// - public int LevelCurrent { get => levelCurrent; set => SetProperty(ref levelCurrent, value); } + public uint LevelCurrent { get => levelCurrent; set => SetProperty(ref levelCurrent, value); } /// - public int LevelTarget { get => levelTarget; set => SetProperty(ref levelTarget, value); } + public uint LevelTarget { get => levelTarget; set => SetProperty(ref levelTarget, value); } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Calculable/CalculableSkill.cs b/src/Snap.Hutao/Snap.Hutao/Model/Calculable/CalculableSkill.cs index a1668b43..0093ce25 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Calculable/CalculableSkill.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Calculable/CalculableSkill.cs @@ -5,6 +5,7 @@ using CommunityToolkit.Mvvm.ComponentModel; using Snap.Hutao.Model.Intrinsic; using Snap.Hutao.Model.Metadata.Avatar; using Snap.Hutao.Model.Metadata.Converter; +using Snap.Hutao.Model.Primitive; using Snap.Hutao.ViewModel.AvatarProperty; namespace Snap.Hutao.Model.Calculable; @@ -15,8 +16,8 @@ namespace Snap.Hutao.Model.Calculable; [HighQuality] internal sealed class CalculableSkill : ObservableObject, ICalculableSkill { - private int levelCurrent; - private int levelTarget; + private uint levelCurrent; + private uint levelTarget; /// /// 构造一个新的可计算的技能 @@ -29,7 +30,7 @@ internal sealed class CalculableSkill : ObservableObject, ICalculableSkill LevelMax = 10; // hard coded 10 here Name = skill.Name; Icon = SkillIconConverter.IconNameToUri(skill.Icon); - Quality = ItemQuality.QUALITY_NONE; + Quality = QualityType.QUALITY_NONE; LevelCurrent = LevelMin; LevelTarget = LevelMax; @@ -46,20 +47,20 @@ internal sealed class CalculableSkill : ObservableObject, ICalculableSkill LevelMax = 10; // hard coded 10 here Name = skill.Name; Icon = skill.Icon; - Quality = ItemQuality.QUALITY_NONE; + Quality = QualityType.QUALITY_NONE; LevelCurrent = LevelMin; LevelTarget = LevelMax; } /// - public int GruopId { get; } + public SkillGroupId GruopId { get; } /// - public int LevelMin { get; } + public uint LevelMin { get; } /// - public int LevelMax { get; } + public uint LevelMax { get; } /// public string Name { get; } @@ -68,11 +69,11 @@ internal sealed class CalculableSkill : ObservableObject, ICalculableSkill public Uri Icon { get; } /// - public ItemQuality Quality { get; } + public QualityType Quality { get; } /// - public int LevelCurrent { get => levelCurrent; set => SetProperty(ref levelCurrent, value); } + public uint LevelCurrent { get => levelCurrent; set => SetProperty(ref levelCurrent, value); } /// - public int LevelTarget { get => levelTarget; set => SetProperty(ref levelTarget, value); } + public uint LevelTarget { get => levelTarget; set => SetProperty(ref levelTarget, value); } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Calculable/CalculableWeapon.cs b/src/Snap.Hutao/Snap.Hutao/Model/Calculable/CalculableWeapon.cs index 938a6d23..aef8eda9 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Calculable/CalculableWeapon.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Calculable/CalculableWeapon.cs @@ -15,8 +15,8 @@ namespace Snap.Hutao.Model.Calculable; [HighQuality] internal class CalculableWeapon : ObservableObject, ICalculableWeapon { - private int levelCurrent; - private int levelTarget; + private uint levelCurrent; + private uint levelTarget; /// /// 构造一个新的可计算武器 @@ -56,10 +56,10 @@ internal class CalculableWeapon : ObservableObject, ICalculableWeapon public WeaponId WeaponId { get; } /// - public int LevelMin { get; } + public uint LevelMin { get; } /// - public int LevelMax { get; } + public uint LevelMax { get; } /// public string Name { get; } @@ -68,11 +68,11 @@ internal class CalculableWeapon : ObservableObject, ICalculableWeapon public Uri Icon { get; } /// - public ItemQuality Quality { get; } + public QualityType Quality { get; } /// - public int LevelCurrent { get => levelCurrent; set => SetProperty(ref levelCurrent, value); } + public uint LevelCurrent { get => levelCurrent; set => SetProperty(ref levelCurrent, value); } /// - public int LevelTarget { get => levelTarget; set => SetProperty(ref levelTarget, value); } + public uint LevelTarget { get => levelTarget; set => SetProperty(ref levelTarget, value); } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Calculable/ICalculable.cs b/src/Snap.Hutao/Snap.Hutao/Model/Calculable/ICalculable.cs index b3cefa82..1b92e545 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Calculable/ICalculable.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Calculable/ICalculable.cs @@ -14,15 +14,15 @@ internal interface ICalculable : INameIcon /// /// 星级 /// - ItemQuality Quality { get; } + QualityType Quality { get; } /// /// 当前等级 /// - int LevelCurrent { get; set; } + uint LevelCurrent { get; set; } /// /// 目标等级 /// - int LevelTarget { get; set; } + uint LevelTarget { get; set; } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Calculable/ICalculableAvatar.cs b/src/Snap.Hutao/Snap.Hutao/Model/Calculable/ICalculableAvatar.cs index 7f888290..1c595729 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Calculable/ICalculableAvatar.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Calculable/ICalculableAvatar.cs @@ -19,12 +19,12 @@ internal interface ICalculableAvatar : ICalculable /// /// 最小等级 /// - int LevelMin { get; } + uint LevelMin { get; } /// /// 最大等级 /// - int LevelMax { get; } + uint LevelMax { get; } /// /// 技能组 diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Calculable/ICalculableSkill.cs b/src/Snap.Hutao/Snap.Hutao/Model/Calculable/ICalculableSkill.cs index 15a1b19a..839a7a0e 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Calculable/ICalculableSkill.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Calculable/ICalculableSkill.cs @@ -1,6 +1,8 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using Snap.Hutao.Model.Primitive; + namespace Snap.Hutao.Model.Calculable; /// @@ -12,15 +14,15 @@ internal interface ICalculableSkill : ICalculable /// /// 技能组Id /// - int GruopId { get; } + SkillGroupId GruopId { get; } /// /// 最小等级 /// - int LevelMin { get; } + uint LevelMin { get; } /// /// 最大等级 /// - int LevelMax { get; } + uint LevelMax { get; } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Calculable/ICalculableWeapon.cs b/src/Snap.Hutao/Snap.Hutao/Model/Calculable/ICalculableWeapon.cs index 2020a532..b0af82b5 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Calculable/ICalculableWeapon.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Calculable/ICalculableWeapon.cs @@ -19,10 +19,10 @@ internal interface ICalculableWeapon : ICalculable /// /// 最小等级 /// - int LevelMin { get; } + uint LevelMin { get; } /// /// 最大等级 /// - int LevelMax { get; } + uint LevelMax { get; } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Entity/Achievement.cs b/src/Snap.Hutao/Snap.Hutao/Model/Entity/Achievement.cs index 8b5febbb..cb2d4dfb 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Entity/Achievement.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Entity/Achievement.cs @@ -37,12 +37,12 @@ internal sealed class Achievement : IEquatable /// /// Id /// - public int Id { get; set; } + public uint Id { get; set; } /// /// 当前进度 /// - public int Current { get; set; } + public uint Current { get; set; } /// /// 完成时间 diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Entity/CultivateEntry.cs b/src/Snap.Hutao/Snap.Hutao/Model/Entity/CultivateEntry.cs index 48d303b2..e986bf09 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Entity/CultivateEntry.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Entity/CultivateEntry.cs @@ -40,7 +40,7 @@ internal sealed class CultivateEntry /// /// 角色/武器/家具 Id /// - public int Id { get; set; } + public uint Id { get; set; } /// /// 创建一个新的养成入口点 @@ -49,7 +49,7 @@ internal sealed class CultivateEntry /// 类型 /// 主Id /// 养成入口点 - public static CultivateEntry Create(in Guid projectId, CultivateType type, int id) + public static CultivateEntry Create(in Guid projectId, CultivateType type, uint id) { return new() { diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Entity/GachaItem.cs b/src/Snap.Hutao/Snap.Hutao/Model/Entity/GachaItem.cs index 4661d460..85799237 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Entity/GachaItem.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Entity/GachaItem.cs @@ -49,7 +49,7 @@ internal sealed class GachaItem /// /// 物品Id /// - public int ItemId { get; set; } + public uint ItemId { get; set; } /// /// 获取时间 @@ -66,12 +66,12 @@ internal sealed class GachaItem /// /// 物品Id /// 物品类型字符串 - public static string GetItemTypeStringByItemId(int itemId) + public static string GetItemTypeStringByItemId(uint itemId) { return itemId.Place() switch { - 8 => "角色", - 5 => "武器", + 8U => "角色", + 5U => "武器", _ => "未知", }; } @@ -83,7 +83,7 @@ internal sealed class GachaItem /// 祈愿物品 /// 物品Id /// 新的祈愿物品 - public static GachaItem Create(in Guid archiveId, GachaLogItem item, int itemId) + public static GachaItem Create(in Guid archiveId, GachaLogItem item, uint itemId) { return new() { @@ -103,7 +103,7 @@ internal sealed class GachaItem /// 祈愿物品 /// 物品Id /// 新的祈愿物品 - public static GachaItem CreateForMajor2Minor2OrLower(in Guid archiveId, UIGFItem item, int itemId) + public static GachaItem CreateForMajor2Minor2OrLower(in Guid archiveId, UIGFItem item, uint itemId) { return new() { @@ -129,7 +129,7 @@ internal sealed class GachaItem ArchiveId = archiveId, GachaType = item.GachaType, QueryType = item.UIGFGachaType, - ItemId = int.Parse(item.ItemId), + ItemId = uint.Parse(item.ItemId), Time = item.Time, Id = item.Id, }; diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Entity/InventoryItem.cs b/src/Snap.Hutao/Snap.Hutao/Model/Entity/InventoryItem.cs index 03c3a703..50f4e8b3 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Entity/InventoryItem.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Entity/InventoryItem.cs @@ -34,7 +34,7 @@ internal sealed class InventoryItem /// /// 物品Id /// - public int ItemId { get; set; } + public uint ItemId { get; set; } /// /// 个数 4294967295 @@ -47,7 +47,7 @@ internal sealed class InventoryItem /// 项目Id /// 物品Id /// 新的个数为0的物品 - public static InventoryItem Create(in Guid projectId, int itemId) + public static InventoryItem Create(in Guid projectId, uint itemId) { return new() { diff --git a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/Achievement/UIAFItem.cs b/src/Snap.Hutao/Snap.Hutao/Model/InterChange/Achievement/UIAFItem.cs index bafe336e..dacbcd45 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/Achievement/UIAFItem.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/InterChange/Achievement/UIAFItem.cs @@ -14,7 +14,7 @@ internal sealed class UIAFItem /// 成就Id /// [JsonPropertyName("id")] - public int Id { get; set; } + public uint Id { get; set; } /// /// 完成时间 @@ -27,7 +27,7 @@ internal sealed class UIAFItem /// 对于progress为1的项,该属性始终为0 /// [JsonPropertyName("current")] - public int Current { get; set; } + public uint Current { get; set; } /// /// 完成状态 diff --git a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/GachaLog/UIGFInfo.cs b/src/Snap.Hutao/Snap.Hutao/Model/InterChange/GachaLog/UIGFInfo.cs index a8bacc4a..19a93699 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/GachaLog/UIGFInfo.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/InterChange/GachaLog/UIGFInfo.cs @@ -27,7 +27,6 @@ internal sealed class UIGFInfo /// 导出的时间戳 /// [JsonPropertyName("export_timestamp")] - [JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)] public long? ExportTimestamp { get; set; } /// diff --git a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/Inventory/UIIFInfo.cs b/src/Snap.Hutao/Snap.Hutao/Model/InterChange/Inventory/UIIFInfo.cs index 00cfa0c7..8e199745 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/Inventory/UIIFInfo.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/InterChange/Inventory/UIIFInfo.cs @@ -27,7 +27,6 @@ internal sealed class UIIFInfo /// 导出的时间戳 /// [JsonPropertyName("export_timestamp")] - [JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)] public long? ExportTimestamp { get; set; } /// diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/GrowCurveType.cs b/src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/GrowCurveType.cs index ddd7079b..66ccf5b2 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/GrowCurveType.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/GrowCurveType.cs @@ -36,37 +36,45 @@ internal enum GrowCurveType GROW_CURVE_HP_2 = 23, GROW_CURVE_ATTACK_2 = 24, GROW_CURVE_HP_ENVIRONMENT = 25, + GROW_CURVE_ATTACK_S5 = 31, GROW_CURVE_ATTACK_S4 = 32, GROW_CURVE_ATTACK_S3 = 33, GROW_CURVE_STRIKE_S5 = 34, + GROW_CURVE_DEFENSE_S5 = 41, GROW_CURVE_DEFENSE_S4 = 42, + GROW_CURVE_ATTACK_101 = 1101, GROW_CURVE_ATTACK_102 = 1102, GROW_CURVE_ATTACK_103 = 1103, GROW_CURVE_ATTACK_104 = 1104, GROW_CURVE_ATTACK_105 = 1105, + GROW_CURVE_ATTACK_201 = 1201, GROW_CURVE_ATTACK_202 = 1202, GROW_CURVE_ATTACK_203 = 1203, GROW_CURVE_ATTACK_204 = 1204, GROW_CURVE_ATTACK_205 = 1205, + GROW_CURVE_ATTACK_301 = 1301, GROW_CURVE_ATTACK_302 = 1302, GROW_CURVE_ATTACK_303 = 1303, GROW_CURVE_ATTACK_304 = 1304, GROW_CURVE_ATTACK_305 = 1305, + GROW_CURVE_CRITICAL_101 = 2101, GROW_CURVE_CRITICAL_102 = 2102, GROW_CURVE_CRITICAL_103 = 2103, GROW_CURVE_CRITICAL_104 = 2104, GROW_CURVE_CRITICAL_105 = 2105, + GROW_CURVE_CRITICAL_201 = 2201, GROW_CURVE_CRITICAL_202 = 2202, GROW_CURVE_CRITICAL_203 = 2203, GROW_CURVE_CRITICAL_204 = 2204, GROW_CURVE_CRITICAL_205 = 2205, + GROW_CURVE_CRITICAL_301 = 2301, GROW_CURVE_CRITICAL_302 = 2302, GROW_CURVE_CRITICAL_303 = 2303, diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/Immutable/IntrinsicImmutables.cs b/src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/Immutable/IntrinsicImmutables.cs index 47d9f869..88f18668 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/Immutable/IntrinsicImmutables.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/Immutable/IntrinsicImmutables.cs @@ -24,7 +24,7 @@ internal static class IntrinsicImmutables /// /// 物品类型 /// - public static readonly ImmutableHashSet ItemQualities = Enum.GetValues().Select(e => e.GetLocalizedDescriptionOrDefault()).OfType().ToImmutableHashSet(); + public static readonly ImmutableHashSet ItemQualities = Enum.GetValues().Select(e => e.GetLocalizedDescriptionOrDefault()).OfType().ToImmutableHashSet(); /// /// 身材类型 diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/MaterialType.cs b/src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/MaterialType.cs index 3ac2fefa..40200b84 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/MaterialType.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/MaterialType.cs @@ -12,6 +12,7 @@ internal enum MaterialType MATERIAL_NONE = 0, MATERIAL_FOOD = 1, MATERIAL_QUEST = 2, + MATERIAL_EXCHANGE = 4, MATERIAL_CONSUME = 5, MATERIAL_EXP_FRUIT = 6, @@ -34,6 +35,7 @@ internal enum MaterialType MATERIAL_FAKE_ABSORBATE = 23, MATERIAL_CONSUME_BATCH_USE = 24, MATERIAL_WOOD = 25, + MATERIAL_FURNITURE_FORMULA = 27, MATERIAL_CHANNELLER_SLAB_BUFF = 28, MATERIAL_FURNITURE_SUITE_FORMULA = 29, @@ -41,7 +43,7 @@ internal enum MaterialType MATERIAL_HOME_SEED = 31, MATERIAL_FISH_BAIT = 32, MATERIAL_FISH_ROD = 33, - MATERIAL_SUMO_BUFF = 34, // never appear + MATERIAL_SUMO_BUFF = 34, // sumo 活动道具,never appear MATERIAL_FIREWORKS = 35, MATERIAL_BGM = 36, MATERIAL_SPICE_FOOD = 37, diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/ItemQuality.cs b/src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/QualityType.cs similarity index 97% rename from src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/ItemQuality.cs rename to src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/QualityType.cs index 489a3f20..4e37baaa 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/ItemQuality.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/QualityType.cs @@ -8,7 +8,7 @@ namespace Snap.Hutao.Model.Intrinsic; /// [HighQuality] [Localization] -internal enum ItemQuality +internal enum QualityType { /// /// 无 diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Item.cs b/src/Snap.Hutao/Snap.Hutao/Model/Item.cs index 3ff05ba7..e82ea419 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Item.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Item.cs @@ -29,5 +29,5 @@ internal class Item : INameIcon /// /// 星级 /// - public ItemQuality Quality { get; set; } + public QualityType Quality { get; set; } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Abstraction/INameQuality.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Abstraction/INameQuality.cs index fc8b60f2..b29640d9 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Abstraction/INameQuality.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Abstraction/INameQuality.cs @@ -19,5 +19,5 @@ internal interface INameQuality /// /// 星级 /// - ItemQuality Quality { get; } + QualityType Quality { get; } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Abstraction/ISummaryItemSource.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Abstraction/ISummaryItemSource.cs index 69b5f3de..2be603a4 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Abstraction/ISummaryItemSource.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Abstraction/ISummaryItemSource.cs @@ -15,7 +15,7 @@ internal interface ISummaryItemSource /// /// 星级 /// - ItemQuality Quality { get; } + QualityType Quality { get; } /// /// 转换到简述统计物品 diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Achievement/Achievement.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Achievement/Achievement.cs index 89f05571..54ed3441 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Achievement/Achievement.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Achievement/Achievement.cs @@ -24,7 +24,7 @@ internal sealed class Achievement /// /// 排序顺序 /// - public int Order { get; set; } + public uint Order { get; set; } /// /// 标题 @@ -44,7 +44,7 @@ internal sealed class Achievement /// /// 总进度 /// - public int Progress { get; set; } + public uint Progress { get; set; } /// /// 图标 diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Achievement/AchievementGoal.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Achievement/AchievementGoal.cs index 9c943822..7c3695e4 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Achievement/AchievementGoal.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Achievement/AchievementGoal.cs @@ -19,7 +19,7 @@ internal sealed class AchievementGoal /// /// 排序顺序 /// - public int Order { get; set; } + public uint Order { get; set; } /// /// 名称 diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Achievement/Reward.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Achievement/Reward.cs index a80a6ce0..40749e14 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Achievement/Reward.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Achievement/Reward.cs @@ -18,5 +18,5 @@ internal sealed class Reward /// /// 数量 /// - public int Count { get; set; } + public uint Count { get; set; } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/Avatar.Implementation.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/Avatar.Implementation.cs index 0b90a050..73db31c0 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/Avatar.Implementation.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/Avatar.Implementation.cs @@ -18,6 +18,7 @@ internal partial class Avatar : IStatisticsItemSource, ISummaryItemSource, IName { /// /// [非元数据] 搭配数据 + /// TODO:Add View suffix. /// [JsonIgnore] public AvatarCollocationView? Collocation { get; set; } @@ -37,7 +38,7 @@ internal partial class Avatar : IStatisticsItemSource, ISummaryItemSource, IName /// 最大等级 /// [SuppressMessage("", "CA1822")] - public int MaxLevel { get => 90; } + public uint MaxLevel { get => 90U; } /// public ICalculableAvatar ToCalculable() diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/Avatar.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/Avatar.cs index 0a228c51..7875b53b 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/Avatar.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/Avatar.cs @@ -26,12 +26,11 @@ internal partial class Avatar /// /// 排序号 /// - public int Sort { get; set; } + public uint Sort { get; set; } /// /// 体型 /// - [JsonEnum(JsonSerializeType.String)] public BodyType Body { get; set; } = default!; /// @@ -62,7 +61,7 @@ internal partial class Avatar /// /// 星级 /// - public ItemQuality Quality { get; set; } + public QualityType Quality { get; set; } /// /// 武器类型 @@ -72,12 +71,12 @@ internal partial class Avatar /// /// 基础数值 /// - public BaseValue BaseValue { get; set; } = default!; + public AvatarBaseValue BaseValue { get; set; } = default!; /// /// 生长曲线 /// - public Dictionary GrowCurves { get; set; } = default!; + public List> GrowCurves { get; set; } = default!; /// /// 技能 diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/AvatarBaseValue.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/AvatarBaseValue.cs new file mode 100644 index 00000000..04bd2365 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/AvatarBaseValue.cs @@ -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; + +/// +/// 角色基础数值 +/// +internal sealed class AvatarBaseValue : BaseValue +{ + public PropertyCurveValue GetPropertyCurveValue(FightProperty fightProperty) + { + // TODO: impl + return null; + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/Costume.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/Costume.cs index b90ce93d..a0005f5a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/Costume.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/Costume.cs @@ -34,7 +34,7 @@ internal sealed class Costume /// /// 图标 /// - public string Icon { get; set; } = default!; + public string FrontIcon { get; set; } = default!; /// /// 侧面图标 diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/FetterInfo.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/FetterInfo.cs index 5ae8899f..c0003efd 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/FetterInfo.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/FetterInfo.cs @@ -25,7 +25,6 @@ internal sealed class FetterInfo /// /// 地区 /// - [JsonEnum(JsonSerializeType.String)] public AssociationType Association { get; set; } = default!; /// @@ -36,12 +35,12 @@ internal sealed class FetterInfo /// /// 生月 /// - public int BirthMonth { get; set; } + public uint BirthMonth { get; set; } /// /// 生日 /// - public int BirthDay { get; set; } + public uint BirthDay { get; set; } /// /// 格式化的生日日期 diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/AvatarIds.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/AvatarIds.cs index dec36089..5f1c79ba 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/AvatarIds.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/AvatarIds.cs @@ -12,6 +12,7 @@ namespace Snap.Hutao.Model.Metadata; [SuppressMessage("", "SA1600")] internal static class AvatarIds { + // 此处的变量名称以 UI_AvatarIcon 为准 public static readonly AvatarId Ayaka = 10000002; public static readonly AvatarId Qin = 10000003; @@ -106,7 +107,7 @@ internal static class AvatarIds Name = "旅行者", Icon = "UI_AvatarIcon_PlayerBoy", SideIcon = "UI_AvatarIcon_Side_PlayerBoy", - Quality = Intrinsic.ItemQuality.QUALITY_ORANGE, + Quality = Intrinsic.QualityType.QUALITY_ORANGE, }, [PlayerGirl] = new() @@ -114,7 +115,7 @@ internal static class AvatarIds Name = "旅行者", Icon = "UI_AvatarIcon_PlayerGirl", SideIcon = "UI_AvatarIcon_Side_PlayerGirl", - Quality = Intrinsic.ItemQuality.QUALITY_ORANGE, + Quality = Intrinsic.QualityType.QUALITY_ORANGE, }, }; } diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/BaseValue.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/BaseValue.cs index 4b5d2cd4..552d96c9 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/BaseValue.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/BaseValue.cs @@ -30,7 +30,7 @@ internal class BaseValue /// /// 战斗属性 /// - public float GetValue(FightProperty fightProperty) + public virtual float GetValue(FightProperty fightProperty) { return fightProperty switch { diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/DescriptionsParametersDescriptor.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/DescriptionsParametersDescriptor.cs index 76c9004e..cce1db7d 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/DescriptionsParametersDescriptor.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/DescriptionsParametersDescriptor.cs @@ -20,7 +20,7 @@ internal sealed partial class DescriptionsParametersDescriptor : ValueConverter< /// 源 /// 等级 /// 特定等级的解释 - public static LevelParameters Convert(DescriptionsParameters from, int level) + public static LevelParameters Convert(DescriptionsParameters from, uint level) { LevelParameters param = from.Parameters.Single(param => param.Level == level); return new LevelParameters($"Lv.{param.Level}", GetParameterDescription(from.Descriptions, param.Parameters)); diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/QualityColorConverter.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/QualityColorConverter.cs index c4ce4ef1..20df90d1 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/QualityColorConverter.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/QualityColorConverter.cs @@ -13,18 +13,18 @@ namespace Snap.Hutao.Model.Metadata.Converter; /// 品质颜色转换器 /// [HighQuality] -internal sealed class QualityColorConverter : ValueConverter +internal sealed class QualityColorConverter : ValueConverter { /// - public override Color Convert(ItemQuality from) + public override Color Convert(QualityType from) { return from switch { - ItemQuality.QUALITY_WHITE => StructMarshal.Color(0xFF72778B), - ItemQuality.QUALITY_GREEN => StructMarshal.Color(0xFF2A8F72), - ItemQuality.QUALITY_BLUE => StructMarshal.Color(0xFF5180CB), - ItemQuality.QUALITY_PURPLE => StructMarshal.Color(0xFFA156E0), - ItemQuality.QUALITY_ORANGE or ItemQuality.QUALITY_ORANGE_SP => StructMarshal.Color(0xFFBC6932), + QualityType.QUALITY_WHITE => StructMarshal.Color(0xFF72778B), + QualityType.QUALITY_GREEN => StructMarshal.Color(0xFF2A8F72), + QualityType.QUALITY_BLUE => StructMarshal.Color(0xFF5180CB), + QualityType.QUALITY_PURPLE => StructMarshal.Color(0xFFA156E0), + QualityType.QUALITY_ORANGE or QualityType.QUALITY_ORANGE_SP => StructMarshal.Color(0xFFBC6932), _ => Colors.Transparent, }; } diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/QualityConverter.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/QualityConverter.cs index 5306edef..39cea05f 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/QualityConverter.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/QualityConverter.cs @@ -10,13 +10,13 @@ namespace Snap.Hutao.Model.Metadata.Converter; /// 物品等级转换器 /// [HighQuality] -internal sealed class QualityConverter : ValueConverter +internal sealed class QualityConverter : ValueConverter { /// - public override Uri Convert(ItemQuality from) + public override Uri Convert(QualityType from) { string name = Enum.GetName(from) ?? from.ToString(); - if (name == nameof(ItemQuality.QUALITY_ORANGE_SP)) + if (name == nameof(QualityType.QUALITY_ORANGE_SP)) { name = "QUALITY_RED"; } diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/GachaEvent.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/GachaEvent.cs index 35ea775b..3cbcc597 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/GachaEvent.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/GachaEvent.cs @@ -21,11 +21,21 @@ internal sealed class GachaEvent /// public string Version { get; set; } = default!; + /// + /// 顺序 + /// + public uint Order { get; set; } + /// /// 卡池图 /// public Uri Banner { get; set; } = default!; + /// + /// 卡池图2 + /// + public Uri Banner2 { get; set; } = default!; + /// /// 开始时间 /// @@ -44,10 +54,10 @@ internal sealed class GachaEvent /// /// 五星列表 /// - public List UpOrangeList { get; set; } = default!; + public List UpOrangeList { get; set; } = default!; /// /// 四星列表 /// - public List UpPurpleList { get; set; } = default!; + public List UpPurpleList { get; set; } = default!; } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/GrowCurve.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/GrowCurve.cs index dffb1d06..e11e55ea 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/GrowCurve.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/GrowCurve.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using Snap.Hutao.Model.Intrinsic; +using Snap.Hutao.Model.Primitive; namespace Snap.Hutao.Model.Metadata; @@ -11,13 +12,23 @@ namespace Snap.Hutao.Model.Metadata; [HighQuality] internal sealed class GrowCurve { + private Dictionary? curveMap; + /// /// 等级 /// - public int Level { get; set; } + public Level Level { get; set; } /// /// 曲线 值相乘 /// - public Dictionary Curves { get; set; } = default!; + public List> Curves { get; set; } = default!; + + /// + /// 曲线映射 + /// + public Dictionary CurveMap + { + get => curveMap ??= Curves.ToDictionary(v => v.Type, v => v.Value); + } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Item/Display.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Item/DisplayItem.cs similarity index 92% rename from src/Snap.Hutao/Snap.Hutao/Model/Metadata/Item/Display.cs rename to src/Snap.Hutao/Snap.Hutao/Model/Metadata/Item/DisplayItem.cs index a9071979..d952a480 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Item/Display.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Item/DisplayItem.cs @@ -10,7 +10,7 @@ namespace Snap.Hutao.Model.Metadata.Item; /// 展示物品 /// [HighQuality] -internal class Display +internal class DisplayItem { /// /// 物品Id @@ -20,7 +20,7 @@ internal class Display /// /// 等级 /// - public ItemQuality RankLevel { get; set; } + public QualityType RankLevel { get; set; } /// /// 物品类型 diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Item/Material.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Item/Material.cs index 131e0462..01501f34 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Item/Material.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Item/Material.cs @@ -11,44 +11,8 @@ namespace Snap.Hutao.Model.Metadata.Item; /// /// 材料 /// -internal sealed class Material : Display +internal sealed class Material : DisplayItem { - private static readonly ImmutableHashSet MondayThursdayItems = new HashSet - { - 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 TuesdayFridayItems = new HashSet - { - 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 WednesdaySaturdayItems = new HashSet - { - 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(); - /// /// 材料类型 /// @@ -66,23 +30,24 @@ internal sealed class Material : Display public bool IsInventoryItem() { // 原质 - if (Id == 112001) + if (Id == 112001U) { return false; } // 摩拉 - if (Id == 202) + if (Id == 202U) { return true; } + // TODO: support non-CHS if (TypeDescription.EndsWith("区域特产")) { return true; } - // TODO: Currently only support CN + // TODO: support non-CHS return TypeDescription switch { "角色与武器培养素材" => true, // 怪物掉落 @@ -106,9 +71,9 @@ internal sealed class Material : Display { return DateTimeOffset.UtcNow.AddHours(4).DayOfWeek switch { - DayOfWeek.Monday or DayOfWeek.Thursday => MondayThursdayItems.Contains(Id), - DayOfWeek.Tuesday or DayOfWeek.Friday => TuesdayFridayItems.Contains(Id), - DayOfWeek.Wednesday or DayOfWeek.Saturday => WednesdaySaturdayItems.Contains(Id), + DayOfWeek.Monday or DayOfWeek.Thursday => Materials.MondayThursdayItems.Contains(Id), + DayOfWeek.Tuesday or DayOfWeek.Friday => Materials.TuesdayFridayItems.Contains(Id), + DayOfWeek.Wednesday or DayOfWeek.Saturday => Materials.WednesdaySaturdayItems.Contains(Id), _ => false, }; } @@ -119,17 +84,17 @@ internal sealed class Material : Display /// DaysOfWeek public DaysOfWeek GetDaysOfWeek() { - if (MondayThursdayItems.Contains(Id)) + if (Materials.MondayThursdayItems.Contains(Id)) { return DaysOfWeek.MondayAndThursday; } - if (TuesdayFridayItems.Contains(Id)) + if (Materials.TuesdayFridayItems.Contains(Id)) { return DaysOfWeek.TuesdayAndFriday; } - if (WednesdaySaturdayItems.Contains(Id)) + if (Materials.WednesdaySaturdayItems.Contains(Id)) { return DaysOfWeek.WednesdayAndSaturday; } diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Item/Materials.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Item/Materials.cs new file mode 100644 index 00000000..ce04c4f3 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Item/Materials.cs @@ -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; + +/// +/// 材料表 +/// +internal static class Materials +{ + private static readonly ImmutableHashSet MondayThursdayItemsInner = new HashSet + { + 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 TuesdayFridayItemsInner = new HashSet + { + 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 WednesdaySaturdayItemsInner = new HashSet + { + 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(); + + /// + /// 周一/周四 + /// + public static ImmutableHashSet MondayThursdayItems { get => MondayThursdayItemsInner; } + + /// + /// 周二/周五 + /// + public static ImmutableHashSet TuesdayFridayItems { get => TuesdayFridayItemsInner; } + + /// + /// 周三/周六 + /// + public static ImmutableHashSet WednesdaySaturdayItems { get => WednesdaySaturdayItemsInner; } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Monster/Monster.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Monster/Monster.cs index 42c3b74b..3ddab034 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Monster/Monster.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Monster/Monster.cs @@ -17,6 +17,11 @@ internal sealed class Monster /// public MonsterId Id { get; set; } + /// + /// 描述 Id + /// + public MonsterDescribeId DescribeId { get; set; } + /// /// 内部代号 /// @@ -60,10 +65,11 @@ internal sealed class Monster /// /// 生长曲线 /// - public Dictionary GrowCurves { get; set; } = default!; + public List> GrowCurves { get; set; } = default!; /// /// 养成物品视图 /// - public List? DropsView { get; set; } + [JsonIgnore] + public List? DropsView { get; set; } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Promote.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Promote.cs index 85670c71..b61de4af 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Promote.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Promote.cs @@ -12,6 +12,8 @@ namespace Snap.Hutao.Model.Metadata; [HighQuality] internal sealed class Promote { + private Dictionary? addPropertyMap; + /// /// Id /// @@ -20,10 +22,18 @@ internal sealed class Promote /// /// 突破等级 /// - public int Level { get; set; } + public PromoteLevel Level { get; set; } /// /// 增加的属性 /// - public Dictionary AddProperties { get; set; } = default!; + public List> AddProperties { get; set; } = default!; + + /// + /// 属性映射 + /// + public Dictionary AddPropertyMap + { + get => addPropertyMap ??= AddProperties.ToDictionary(a => a.Type, a => a.Value); + } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Reliquary/Reliquary.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Reliquary/Reliquary.cs index 4bb61753..5a2fa5ff 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Reliquary/Reliquary.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Reliquary/Reliquary.cs @@ -20,7 +20,7 @@ internal sealed class Reliquary /// /// 允许出现的等级 /// - public ItemQuality RankLevel { get; set; } = default!; + public QualityType RankLevel { get; set; } = default!; /// /// 套装Id diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Reliquary/ReliquaryAffixWeight.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Reliquary/ReliquaryAffixWeight.cs new file mode 100644 index 00000000..f1212ee9 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Reliquary/ReliquaryAffixWeight.cs @@ -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; + +/// +/// 圣遗物词条权重 +/// +internal sealed class ReliquaryAffixWeight +{ + /// + /// 角色 Id + /// + public AvatarId AvatarId { get; set; } + + /// + /// 生命值 + /// + public float HpPercent { get; set; } + + /// + /// 攻击力 + /// + public float AttackPercent { get; set; } + + /// + /// 防御力 + /// + public float DefensePercent { get; set; } + + /// + /// 暴击率 + /// + public float Critical { get; set; } + + /// + /// 暴击伤害 + /// + public float CriticalHurt { get; set; } + + /// + /// 元素精通 + /// + public float ElementMastery { get; set; } + + /// + /// 元素充能效率 + /// + public float ChargeEfficiency { get; set; } + + /// + /// 治疗加成 + /// + public float HealAdd { get; set; } + + /// + /// 物理伤害加成 + /// + public float PhysicalAddHurt { get; set; } + + /// + /// 伤害加成 + /// + public float AddHurt { get; set; } + + /// + /// 元素类型 + /// + public ElementType ElementType { get; set; } + + /// + /// 获取权重 + /// + /// 属性 + /// 权重 + 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, + }; + } + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Reliquary/ReliquaryMainAffixLevel.PropertyMap.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Reliquary/ReliquaryMainAffixLevel.PropertyMap.cs new file mode 100644 index 00000000..342b312a --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Reliquary/ReliquaryMainAffixLevel.PropertyMap.cs @@ -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; + +/// +/// 属性映射 +/// +internal sealed partial class ReliquaryMainAffixLevel +{ + private Dictionary? propertyMap; + + /// + /// 属性映射 + /// + public Dictionary PropertyMap + { + get => propertyMap ??= Properties.ToDictionary(t => t.Type, t => t.Value); + } +} diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Reliquary/ReliquaryLevel.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Reliquary/ReliquaryMainAffixLevel.cs similarity index 64% rename from src/Snap.Hutao/Snap.Hutao/Model/Metadata/Reliquary/ReliquaryLevel.cs rename to src/Snap.Hutao/Snap.Hutao/Model/Metadata/Reliquary/ReliquaryMainAffixLevel.cs index 740fece8..3523ca04 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Reliquary/ReliquaryLevel.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Reliquary/ReliquaryMainAffixLevel.cs @@ -9,20 +9,20 @@ namespace Snap.Hutao.Model.Metadata.Reliquary; /// 圣遗物等级 /// [HighQuality] -internal sealed class ReliquaryLevel +internal sealed partial class ReliquaryMainAffixLevel { /// /// 品质 /// - public ItemQuality Quality { get; set; } + public QualityType Rank { get; set; } /// /// 等级 1-21 /// - public int Level { get; set; } + public uint Level { get; set; } /// /// 属性 /// - public Dictionary Properties { get; set; } = default!; + public List> Properties { get; set; } = default!; } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Reliquary/ReliquarySet.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Reliquary/ReliquarySet.cs index 07a01baa..3398e9b4 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Reliquary/ReliquarySet.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Reliquary/ReliquarySet.cs @@ -14,7 +14,7 @@ internal sealed class ReliquarySet /// /// 套装Id /// - public int SetId { get; set; } + public ReliquarySetId SetId { get; set; } /// /// 装备被动Id diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Reliquary/ReliquaryAffix.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Reliquary/ReliquarySubAffix.cs similarity index 77% rename from src/Snap.Hutao/Snap.Hutao/Model/Metadata/Reliquary/ReliquaryAffix.cs rename to src/Snap.Hutao/Snap.Hutao/Model/Metadata/Reliquary/ReliquarySubAffix.cs index 34c1bb2c..a76eb698 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Reliquary/ReliquaryAffix.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Reliquary/ReliquarySubAffix.cs @@ -9,12 +9,12 @@ namespace Snap.Hutao.Model.Metadata.Reliquary; /// 圣遗物突破属性 /// [HighQuality] -internal sealed class ReliquaryAffix : ReliquaryMainAffix +internal sealed class ReliquarySubAffix : ReliquaryMainAffix { /// /// Id /// - public new ReliquaryAffixId Id { get; set; } + public new ReliquarySubAffixId Id { get; set; } /// /// 值 diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Tower/TowerFloor.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Tower/TowerFloor.cs new file mode 100644 index 00000000..4fc7f280 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Tower/TowerFloor.cs @@ -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; + +/// +/// 深渊 层 +/// +internal sealed class TowerFloor +{ + /// + /// Id + /// + public TowerFloorId Id { get; set; } + + /// + /// 编号 [1-12] + /// + public uint Index { get; set; } + + /// + /// 深渊间分组编号 + /// + public TowerLevelGroupId LevelGroupId { get; set; } + + /// + /// 背景图片 + /// + public string Background { get; set; } = default!; +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Tower/TowerLevel.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Tower/TowerLevel.cs new file mode 100644 index 00000000..0848167f --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Tower/TowerLevel.cs @@ -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; + +/// +/// 深渊 间 +/// +internal sealed class TowerLevel +{ + /// + /// Id + /// + public TowerLevelId Id { get; set; } + + /// + /// 深渊间分组编号 + /// + public TowerLevelGroupId GroupId { get; set; } + + /// + /// 编号 + /// + public uint Index { get; set; } + + /// + /// 怪物等级 + /// + public uint MonsterLevel { get; set; } + + /// + /// 上半怪物预览 + /// + public List FirstMonsters { get; set; } = default!; + + /// + /// 下半怪物预览 + /// + public List SecondMonsters { get; set; } = default!; +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Tower/TowerSchedule.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Tower/TowerSchedule.cs new file mode 100644 index 00000000..c6b95efd --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Tower/TowerSchedule.cs @@ -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; + +/// +/// 深渊 计划 +/// +internal sealed class TowerSchedule +{ + /// + /// 计划 Id + /// + public TowerScheduleId Id { get; set; } + + /// + /// 层 Id 表 + /// + public List FloorIds { get; set; } = default!; + + /// + /// 开始时间 + /// + public DateTimeOffset Open { get; set; } + + /// + /// 结束时间 + /// + public DateTimeOffset Close { get; set; } + + /// + /// 渊月祝福 + /// + public string BuffName { get; set; } = default!; + + /// + /// 描述 + /// + public List Descriptions { get; set; } = default!; + + /// + /// 图标 + /// + public string Icon { get; set; } = default!; +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/TypeValue.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/TypeValue.cs new file mode 100644 index 00000000..5ed06b0b --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/TypeValue.cs @@ -0,0 +1,33 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +namespace Snap.Hutao.Model.Metadata; + +/// +/// 类型与值 +/// +/// 类型 +/// +internal class TypeValue +{ + /// + /// 构造一个新的类型与值 + /// + /// 类型 + /// 值 + public TypeValue(TType type, TValue value) + { + Type = type; + Value = value; + } + + /// + /// 类型 + /// + public TType Type { get; set; } + + /// + /// 值 + /// + public TValue Value { get; set; } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Weapon/GrowCurveTypeValue.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Weapon/GrowCurveTypeValue.cs deleted file mode 100644 index aba413a2..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Weapon/GrowCurveTypeValue.cs +++ /dev/null @@ -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; - -/// -/// 生长曲线与值 -/// -[HighQuality] -internal sealed class GrowCurveTypeValue -{ - /// - /// 类型 - /// - public GrowCurveType Type { get; set; } - - /// - /// 值 - /// - public float Value { get; set; } -} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Weapon/Weapon.Implementation.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Weapon/Weapon.Implementation.cs index 500fb366..87b1b1e3 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Weapon/Weapon.Implementation.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Weapon/Weapon.Implementation.cs @@ -23,7 +23,7 @@ internal sealed partial class Weapon : IStatisticsItemSource, ISummaryItemSource /// [JsonIgnore] - public ItemQuality Quality + public QualityType Quality { get => RankLevel; } @@ -31,7 +31,7 @@ internal sealed partial class Weapon : IStatisticsItemSource, ISummaryItemSource /// /// 最大等级 /// - internal int MaxLevel { get => ((int)Quality) >= 3 ? 90 : 70; } + internal uint MaxLevel { get => ((int)Quality) >= 3 ? 90U : 70U; } /// public ICalculableWeapon ToCalculable() diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Weapon/Weapon.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Weapon/Weapon.cs index 19b0d9b1..01cc7e55 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Weapon/Weapon.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Weapon/Weapon.cs @@ -30,7 +30,7 @@ internal sealed partial class Weapon /// /// 等级 /// - public ItemQuality RankLevel { get; set; } + public QualityType RankLevel { get; set; } /// /// 名称 @@ -55,7 +55,7 @@ internal sealed partial class Weapon /// /// 生长曲线 /// - public Dictionary GrowCurves { get; set; } = default!; + public List GrowCurves { get; set; } = default!; /// /// 被动信息, 无被动的武器为 diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Weapon/WeaponTypeValue.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Weapon/WeaponTypeValue.cs new file mode 100644 index 00000000..902c2f1d --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Weapon/WeaponTypeValue.cs @@ -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; + +/// +/// 武器曲线值 +/// +internal sealed class WeaponTypeValue : TypeValue +{ + /// + /// 构造一个新的武器曲线值 + /// + /// 属性类型 + /// 曲线类型 + /// 初始值 + public WeaponTypeValue(FightProperty type, GrowCurveType value, float initValue) + : base(type, value) + { + InitValue = initValue; + } + + /// + /// 初始值 + /// + public float InitValue { get; set; } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Primitive/Converter/IdentityConverter.cs b/src/Snap.Hutao/Snap.Hutao/Model/Primitive/Converter/IdentityConverter.cs new file mode 100644 index 00000000..579be071 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/Primitive/Converter/IdentityConverter.cs @@ -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; + +/// +/// Id 转换器 +/// +/// 包装类型 +internal unsafe sealed class IdentityConverter : JsonConverter + where TWrapper : unmanaged +{ + /// + public override TWrapper Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + uint value = JsonSerializer.Deserialize(ref reader, options); + return *(TWrapper*)&value; + } + + /// + 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(); + } + + /// + public override void Write(Utf8JsonWriter writer, TWrapper value, JsonSerializerOptions options) + { + JsonSerializer.Serialize(writer, *(uint*)&value, options); + } + + /// + public override void WriteAsPropertyName(Utf8JsonWriter writer, TWrapper value, JsonSerializerOptions options) + { + writer.WritePropertyName((*(uint*)&value).ToString()); + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementService.cs index c3aea34c..9b42a5b7 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Achievement/AchievementService.cs @@ -34,7 +34,7 @@ internal sealed partial class AchievementService : IAchievementService /// public List GetAchievements(AchievementArchive archive, List metadata) { - Dictionary entityMap; + Dictionary entityMap; try { using (IServiceScope scope = serviceProvider.CreateScope()) @@ -43,7 +43,7 @@ internal sealed partial class AchievementService : IAchievementService entityMap = appDbContext.Achievements .Where(a => a.ArchiveId == archive.InnerId) .AsEnumerable() - .ToDictionary(a => a.Id); + .ToDictionary(a => (AchievementId)a.Id); } } catch (ArgumentException ex) diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoDbBulkOperation.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoDbBulkOperation.cs index ffd9e1ba..6a438af7 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoDbBulkOperation.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/AvatarInfoDbBulkOperation.cs @@ -4,6 +4,7 @@ using Snap.Hutao.Core.Database; using Snap.Hutao.Model.Entity.Database; using Snap.Hutao.Model.Metadata; +using Snap.Hutao.Model.Primitive; using Snap.Hutao.Service.AvatarInfo.Transformer; using Snap.Hutao.Service.Metadata; using Snap.Hutao.ViewModel.User; @@ -202,7 +203,7 @@ internal sealed partial class AvatarInfoDbBulkOperation } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void AddOrUpdateAvatarInfo(ModelAvatarInfo? entity, int avatarId, string uid, AppDbContext appDbContext, IAvatarInfoTransformer transformer, TSource source) + private static void AddOrUpdateAvatarInfo(ModelAvatarInfo? entity, AvatarId avatarId, string uid, AppDbContext appDbContext, IAvatarInfoTransformer transformer, TSource source) { if (entity == null) { diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/AffixWeight.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/AffixWeight.cs index f6f6476c..66904676 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/AffixWeight.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/AffixWeight.cs @@ -26,7 +26,7 @@ internal sealed class AffixWeight : Dictionary /// 治疗加成 /// 名称 public AffixWeight( - int avatarId, + uint avatarId, float hp, float atk, float def, diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryAvatarFactory.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryAvatarFactory.cs index 74fb2401..856c6b6d 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryAvatarFactory.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryAvatarFactory.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using Snap.Hutao.Model.Intrinsic; +using Snap.Hutao.Model.Primitive; using Snap.Hutao.Model.Metadata.Converter; using Snap.Hutao.ViewModel.AvatarProperty; 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); // Set to costume icon - propertyAvatar.Icon = AvatarIconConverter.IconNameToUri(costume.Icon); + propertyAvatar.Icon = AvatarIconConverter.IconNameToUri(costume.FrontIcon); propertyAvatar.SideIcon = AvatarIconConverter.IconNameToUri(costume.SideIcon); } else @@ -116,9 +117,9 @@ internal sealed class SummaryAvatarFactory { MetadataWeapon weapon = metadataContext.IdWeaponMap[equip.ItemId]; - // AffixMap can be empty when it's a white weapon. - KeyValuePair? idLevel = equip.Weapon!.AffixMap?.Single(); - int affixLevel = idLevel?.Value ?? 0; + // AffixMap can be null when it's a white weapon. + KeyValuePair? idLevel = equip.Weapon!.AffixMap?.Single(); + uint affixLevel = idLevel?.Value ?? 0U; WeaponStat? mainStat = equip.Flat.WeaponStats?.ElementAtOrDefault(0); WeaponStat? subStat = equip.Flat.WeaponStats?.ElementAtOrDefault(1); @@ -145,7 +146,7 @@ internal sealed class SummaryAvatarFactory Description = weapon.Description, // EquipBase - Level = $"Lv.{equip.Weapon!.Level}", + Level = $"Lv.{equip.Weapon!.Level.Value}", Quality = weapon.Quality, MainProperty = mainStat != null ? FightPropertyFormat.ToNameValue(mainStat.AppendPropId, mainStat.StatValue) : default!, diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryFactory.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryFactory.cs index ed0324c0..c06ed801 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryFactory.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryFactory.cs @@ -26,7 +26,7 @@ internal sealed partial class SummaryFactory : ISummaryFactory IdAvatarMap = await metadataService.GetIdToAvatarMapAsync(token).ConfigureAwait(false), IdWeaponMap = await metadataService.GetIdToWeaponMapAsync(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), Reliquaries = await metadataService.GetReliquariesAsync(token).ConfigureAwait(false), }; diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryHelper.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryHelper.cs index 8c254c99..e8f6906c 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryHelper.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryHelper.cs @@ -39,29 +39,26 @@ internal static class SummaryHelper /// 额外提升等级映射 /// 技能列表 /// 技能 - public static List CreateSkills(Dictionary skillLevelMap, Dictionary? proudSkillExtraLevelMap, List proudSkills) + public static List CreateSkills(Dictionary skillLevelMap, Dictionary? proudSkillExtraLevelMap, List proudSkills) { if (skillLevelMap == null) { return new(); } - Dictionary skillExtraLeveledMap = new(skillLevelMap); + Dictionary skillExtraLeveledMap = new(skillLevelMap); if (proudSkillExtraLevelMap != null) { - foreach ((string skillGroupIdString, int extraLevel) in proudSkillExtraLevelMap) + foreach ((SkillGroupId groupId, SkillLevel extraLevel) in proudSkillExtraLevelMap) { - SkillGroupId skillGroupId = int.Parse(skillGroupIdString); - SkillId skillId = proudSkills.Single(p => p.GroupId == skillGroupId).Id; - - skillExtraLeveledMap.Increase($"{skillId.Value}", extraLevel); + skillExtraLeveledMap.IncreaseValue(proudSkills.Single(p => p.GroupId == groupId).Id, extraLevel); } } return proudSkills.SelectList(proudableSkill => { - string skillId = $"{proudableSkill.Id.Value}"; + SkillId skillId = proudableSkill.Id; return new SkillView() { @@ -81,10 +78,10 @@ internal static class SummaryHelper /// /// 属性Id /// 最大属性Id - public static int GetAffixMaxId(int appendId) + public static ReliquarySubAffixId GetAffixMaxId(in ReliquarySubAffixId appendId) { - int value = appendId / 100000; - int max = value switch + uint value = (uint)appendId / 100000U; + uint max = value switch { 1 => 2, 2 => 3, @@ -100,10 +97,10 @@ internal static class SummaryHelper /// /// id /// 分数 - public static float GetPercentSubAffixScore(int appendId) + public static float GetPercentSubAffixScore(ReliquarySubAffixId appendId) { - int maxId = GetAffixMaxId(appendId); - int delta = maxId - appendId; + uint maxId = GetAffixMaxId(appendId); + uint delta = maxId - appendId; return (maxId / 100000, delta) switch { diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryMetadataContext.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryMetadataContext.cs index 9cbab40d..612c3448 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryMetadataContext.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryMetadataContext.cs @@ -34,12 +34,12 @@ internal sealed class SummaryMetadataContext /// /// 圣遗物副属性映射 /// - public Dictionary IdReliquaryAffixMap { get; set; } = default!; + public Dictionary IdReliquarySubAffixMap { get; set; } = default!; /// /// 圣遗物等级 /// - public List ReliqueryLevels { get; set; } = default!; + public List ReliqueryLevels { get; set; } = default!; /// /// 圣遗物 diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryReliquaryFactory.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryReliquaryFactory.cs index 06c851c6..90c248bc 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryReliquaryFactory.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/SummaryReliquaryFactory.cs @@ -5,11 +5,12 @@ using Snap.Hutao.Model.Intrinsic; using Snap.Hutao.Model.Intrinsic.Format; using Snap.Hutao.Model.Metadata.Converter; using Snap.Hutao.Model.Metadata.Reliquary; +using Snap.Hutao.Model.Primitive; using Snap.Hutao.ViewModel.AvatarProperty; using Snap.Hutao.Web.Enka.Model; using System.Runtime.InteropServices; 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 PropertyReliquary = Snap.Hutao.ViewModel.AvatarProperty.ReliquaryView; @@ -67,11 +68,10 @@ internal sealed class SummaryReliquaryFactory result.PrimarySubProperties = new(span[..^affixCount].ToArray()); result.SecondarySubProperties = new(span[^affixCount..].ToArray()); result.ComposedSubProperties = equip.Flat.ReliquarySubstats!.SelectList(CreateComposedSubProperty); - - ReliquaryLevel relicLevel = metadataContext.ReliqueryLevels.Single(r => r.Level == equip.Reliquary!.Level && r.Quality == reliquary.RankLevel); + ReliquaryMainAffixLevel relicLevel = metadataContext.ReliqueryLevels.Single(r => r.Level == equip.Reliquary!.Level && r.Rank == reliquary.RankLevel); 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); } @@ -81,46 +81,46 @@ internal sealed class SummaryReliquaryFactory 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, - (ItemQuality.QUALITY_ORANGE, > 16) => 4, - (ItemQuality.QUALITY_ORANGE, > 12) => 3, - (ItemQuality.QUALITY_ORANGE, > 8) => 2, - (ItemQuality.QUALITY_ORANGE, > 4) => 1, - (ItemQuality.QUALITY_ORANGE, _) => 0, + (QualityType.QUALITY_ORANGE, > 20U) => 5, + (QualityType.QUALITY_ORANGE, > 16U) => 4, + (QualityType.QUALITY_ORANGE, > 12U) => 3, + (QualityType.QUALITY_ORANGE, > 8U) => 2, + (QualityType.QUALITY_ORANGE, > 4U) => 1, + (QualityType.QUALITY_ORANGE, _) => 0, - (ItemQuality.QUALITY_PURPLE, > 16) => 4, - (ItemQuality.QUALITY_PURPLE, > 12) => 3, - (ItemQuality.QUALITY_PURPLE, > 8) => 2, - (ItemQuality.QUALITY_PURPLE, > 4) => 1, - (ItemQuality.QUALITY_PURPLE, _) => 0, + (QualityType.QUALITY_PURPLE, > 16U) => 4, + (QualityType.QUALITY_PURPLE, > 12U) => 3, + (QualityType.QUALITY_PURPLE, > 8U) => 2, + (QualityType.QUALITY_PURPLE, > 4U) => 1, + (QualityType.QUALITY_PURPLE, _) => 0, - (ItemQuality.QUALITY_BLUE, > 12) => 3, - (ItemQuality.QUALITY_BLUE, > 8) => 2, - (ItemQuality.QUALITY_BLUE, > 4) => 1, - (ItemQuality.QUALITY_BLUE, _) => 0, + (QualityType.QUALITY_BLUE, > 12U) => 3, + (QualityType.QUALITY_BLUE, > 8U) => 2, + (QualityType.QUALITY_BLUE, > 4U) => 1, + (QualityType.QUALITY_BLUE, _) => 0, - (ItemQuality.QUALITY_GREEN, > 4) => 1, - (ItemQuality.QUALITY_GREEN, _) => 0, + (QualityType.QUALITY_GREEN, > 4U) => 1, + (QualityType.QUALITY_GREEN, _) => 0, - (ItemQuality.QUALITY_WHITE, > 4) => 1, - (ItemQuality.QUALITY_WHITE, _) => 0, + (QualityType.QUALITY_WHITE, > 4U) => 1, + (QualityType.QUALITY_WHITE, _) => 0, _ => 0, }; } - private float ScoreReliquary(FightProperty property, MetadataReliquary reliquary, ReliquaryLevel relicLevel, List subProperties) + private float ScoreReliquary(FightProperty property, MetadataReliquary reliquary, ReliquaryMainAffixLevel relicLevel, List subProperties) { // 沙 杯 头 // equip.Flat.EquipType is EquipType.EQUIP_SHOES or EquipType.EQUIP_RING or EquipType.EQUIP_DRESS if ((int)equip.Flat.EquipType > 3) { 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 score = subProperties.Sum(p => p.Score); @@ -151,9 +151,10 @@ internal sealed class SummaryReliquaryFactory 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; return new( @@ -162,9 +163,9 @@ internal sealed class SummaryReliquaryFactory 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(); float weight = weightConfig.GetValueOrDefault(affix.Type) / 100F; @@ -179,7 +180,7 @@ internal sealed class SummaryReliquaryFactory weight = weightConfig.GetValueOrDefault(affix.Type + 1) / 100F; // 最大同属性百分比数值 最大同属性百分比Id 第四五位是战斗属性位 - MetadataReliquaryAffix maxPercentAffix = metadataContext.IdReliquaryAffixMap[SummaryHelper.GetAffixMaxId(appendId + 10)]; + MetadataReliquaryAffix maxPercentAffix = metadataContext.IdReliquarySubAffixMap[SummaryHelper.GetAffixMaxId(appendId + 10U)]; float equalScore = equalPercent / maxPercentAffix.Value; return weight * equalScore * 100; diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Transformer/CalculateAvatarDetailAvatarInfoTransformer.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Transformer/CalculateAvatarDetailAvatarInfoTransformer.cs index 1041ad72..493c7fc8 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Transformer/CalculateAvatarDetailAvatarInfoTransformer.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Transformer/CalculateAvatarDetailAvatarInfoTransformer.cs @@ -1,6 +1,7 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using Snap.Hutao.Model.Primitive; using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate; 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) { // 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); } } diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Transformer/GameRecordCharacterAvatarInfoTransformer.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Transformer/GameRecordCharacterAvatarInfoTransformer.cs index ac493b69..be4cdb66 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Transformer/GameRecordCharacterAvatarInfoTransformer.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Transformer/GameRecordCharacterAvatarInfoTransformer.cs @@ -57,7 +57,10 @@ internal sealed class GameRecordCharacterAvatarInfoTransformer : IAvatarInfoTran equip.Weapon = new() { 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 diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationService.cs index 977c3dad..96dd6742 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationService.cs @@ -186,7 +186,7 @@ internal sealed partial class CultivationService : ICultivationService } /// - public async Task SaveConsumptionAsync(CultivateType type, int itemId, List items) + public async Task SaveConsumptionAsync(CultivateType type, uint itemId, List items) { if (items.Count == 0) { diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/ICultivationService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/ICultivationService.cs index d0c4f0cc..8ce4e53e 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/ICultivationService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/ICultivationService.cs @@ -71,7 +71,7 @@ internal interface ICultivationService /// 主Id /// 待存物品 /// 是否保存成功 - Task SaveConsumptionAsync(CultivateType type, int itemId, List items); + Task SaveConsumptionAsync(CultivateType type, uint itemId, List items); /// /// 保存养成物品状态 diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/GachaStatisticsFactory.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/GachaStatisticsFactory.cs index 96e6cee3..273800cc 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/GachaStatisticsFactory.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/GachaStatisticsFactory.cs @@ -60,19 +60,19 @@ internal sealed partial class GachaStatisticsFactory : IGachaStatisticsFactory // It's an avatar switch (item.ItemId.Place()) { - case 8: + case 8U: { Avatar avatar = context.IdAvatarMap[item.ItemId]; bool isUp = false; switch (avatar.Quality) { - case ItemQuality.QUALITY_ORANGE: - orangeAvatarCounter.Increase(avatar); + case QualityType.QUALITY_ORANGE: + orangeAvatarCounter.IncreaseOne(avatar); isUp = targetHistoryWishBuilder?.IncreaseOrange(avatar) ?? false; break; - case ItemQuality.QUALITY_PURPLE: - purpleAvatarCounter.Increase(avatar); + case QualityType.QUALITY_PURPLE: + purpleAvatarCounter.IncreaseOne(avatar); targetHistoryWishBuilder?.IncreasePurple(avatar); break; } @@ -83,24 +83,24 @@ internal sealed partial class GachaStatisticsFactory : IGachaStatisticsFactory break; } - case 5: + case 5U: { Weapon weapon = context.IdWeaponMap[item.ItemId]; bool isUp = false; switch (weapon.RankLevel) { - case ItemQuality.QUALITY_ORANGE: + case QualityType.QUALITY_ORANGE: isUp = targetHistoryWishBuilder?.IncreaseOrange(weapon) ?? false; - orangeWeaponCounter.Increase(weapon); + orangeWeaponCounter.IncreaseOne(weapon); break; - case ItemQuality.QUALITY_PURPLE: + case QualityType.QUALITY_PURPLE: targetHistoryWishBuilder?.IncreasePurple(weapon); - purpleWeaponCounter.Increase(weapon); + purpleWeaponCounter.IncreaseOne(weapon); break; - case ItemQuality.QUALITY_BLUE: + case QualityType.QUALITY_BLUE: targetHistoryWishBuilder?.IncreaseBlue(weapon); - blueWeaponCounter.Increase(weapon); + blueWeaponCounter.IncreaseOne(weapon); break; } diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/GachaStatisticsSlimFactory.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/GachaStatisticsSlimFactory.cs index 04c35179..e306f135 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/GachaStatisticsSlimFactory.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/GachaStatisticsSlimFactory.cs @@ -73,15 +73,15 @@ internal sealed partial class GachaStatisticsSlimFactory : IGachaStatisticsSlimF { switch (nameQuality.Quality) { - case ItemQuality.QUALITY_ORANGE: + case QualityType.QUALITY_ORANGE: orangeTracker = 0; ++purpleTracker; break; - case ItemQuality.QUALITY_PURPLE: + case QualityType.QUALITY_PURPLE: ++orangeTracker; purpleTracker = 0; break; - case ItemQuality.QUALITY_BLUE: + case QualityType.QUALITY_BLUE: ++orangeTracker; ++purpleTracker; break; diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/HistoryWishBuilder.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/HistoryWishBuilder.cs index 2e1553c7..35b44267 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/HistoryWishBuilder.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/HistoryWishBuilder.cs @@ -71,10 +71,10 @@ internal sealed class HistoryWishBuilder /// 是否为Up物品 public bool IncreaseOrange(IStatisticsItemSource item) { - orangeCounter.Increase(item); + orangeCounter.IncreaseOne(item); ++totalCountTracker; - return orangeUpCounter.TryIncrease(item); + return orangeUpCounter.TryIncreaseOne(item); } /// @@ -83,8 +83,8 @@ internal sealed class HistoryWishBuilder /// 物品 public void IncreasePurple(IStatisticsItemSource item) { - purpleUpCounter.TryIncrease(item); - purpleCounter.Increase(item); + purpleUpCounter.TryIncreaseOne(item); + purpleCounter.IncreaseOne(item); ++totalCountTracker; } @@ -94,7 +94,7 @@ internal sealed class HistoryWishBuilder /// 武器 public void IncreaseBlue(IStatisticsItemSource item) { - blueCounter.Increase(item); + blueCounter.IncreaseOne(item); ++totalCountTracker; } diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/TypedWishSummaryBuilder.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/TypedWishSummaryBuilder.cs index 71cc466b..9b14e459 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/TypedWishSummaryBuilder.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/TypedWishSummaryBuilder.cs @@ -87,7 +87,7 @@ internal sealed class TypedWishSummaryBuilder switch (source.Quality) { - case ItemQuality.QUALITY_ORANGE: + case QualityType.QUALITY_ORANGE: { TrackMinMaxOrangePull(lastOrangePullTracker); averageOrangePullTracker.Add(lastOrangePullTracker); @@ -105,14 +105,14 @@ internal sealed class TypedWishSummaryBuilder break; } - case ItemQuality.QUALITY_PURPLE: + case QualityType.QUALITY_PURPLE: { lastPurplePullTracker = 0; ++totalPurplePullTracker; break; } - case ItemQuality.QUALITY_BLUE: + case QualityType.QUALITY_BLUE: { ++totalBluePullTracker; break; diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogServiceContext.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogServiceContext.cs index 2520a94d..541636ce 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogServiceContext.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogServiceContext.cs @@ -104,13 +104,13 @@ internal readonly struct GachaLogServiceContext /// /// Id /// 名称星级 - public INameQuality GetNameQualityByItemId(int id) + public INameQuality GetNameQualityByItemId(uint id) { - int place = id.Place(); + uint place = id.Place(); return place switch { - 8 => IdAvatarMap![id], - 5 => IdWeaponMap![id], + 8U => IdAvatarMap![id], + 5U => IdWeaponMap![id], _ => throw Must.NeverHappen($"Id places: {place}"), }; } @@ -121,13 +121,13 @@ internal readonly struct GachaLogServiceContext /// /// 祈愿物品 /// 物品 Id - public int GetItemId(GachaLogItem item) + public uint GetItemId(GachaLogItem item) { return item.ItemType switch { "角色" => NameAvatarMap!.GetValueOrDefault(item.Name)?.Id ?? 0, "武器" => NameWeaponMap!.GetValueOrDefault(item.Name)?.Id ?? 0, - _ => 0, + _ => 0U, }; } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/Package/PackageConverter.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/Package/PackageConverter.cs index 22400011..8b40d5bc 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/Package/PackageConverter.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/Package/PackageConverter.cs @@ -4,6 +4,7 @@ using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient; using Snap.Hutao.Core.ExceptionService; using Snap.Hutao.Core.IO; +using Snap.Hutao.Core.IO.Hashing; using Snap.Hutao.Service.Notification; using Snap.Hutao.Web.Hoyolab.SdkStatic.Hk4e.Launcher; using System.IO; @@ -240,7 +241,7 @@ internal sealed partial class PackageConverter { 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) { // Valid, move it to target path @@ -270,7 +271,7 @@ internal sealed partial class PackageConverter StreamCopyWorker streamCopyWorker = new(webStream, fileStream, bytesRead => new(info.Target, bytesRead, totalBytes)); await streamCopyWorker.CopyAsync(progress).ConfigureAwait(false); 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)) { return; diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Game/ProcessInterop.cs b/src/Snap.Hutao/Snap.Hutao/Service/Game/ProcessInterop.cs index efded4c2..a3ab702c 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Game/ProcessInterop.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Game/ProcessInterop.cs @@ -58,7 +58,7 @@ internal static class ProcessInterop public static Task UnlockFpsAsync(IServiceProvider serviceProvider, Process game) { IGameFpsUnlocker unlocker = serviceProvider.CreateInstance(game); - UnlockTimingOptions options = new(100, 10000, 3000); + UnlockTimingOptions options = new(100, 20000, 3000); return unlocker.UnlockAsync(options); } diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/IMetadataService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/IMetadataService.cs index c7d3406d..20a7dbb5 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/IMetadataService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/IMetadataService.cs @@ -90,14 +90,14 @@ internal interface IMetadataService : ICastableService /// /// 取消令牌 /// 圣遗物强化属性列表 - ValueTask> GetReliquaryAffixesAsync(CancellationToken token = default); + ValueTask> GetReliquarySubAffixesAsync(CancellationToken token = default); /// /// 异步获取圣遗物等级数据 /// /// 取消令牌 /// 圣遗物等级数据 - ValueTask> GetReliquaryLevelsAsync(CancellationToken token = default); + ValueTask> GetReliquaryLevelsAsync(CancellationToken token = default); /// /// 异步获取圣遗物主属性强化属性列表 @@ -156,7 +156,7 @@ internal interface IMetadataService : ICastableService /// /// 取消令牌 /// 显示与材料映射 - ValueTask> GetIdToDisplayAndMaterialMapAsync(CancellationToken token = default); + ValueTask> GetIdToDisplayAndMaterialMapAsync(CancellationToken token = default); /// /// 异步获取Id到材料的字典 @@ -170,7 +170,7 @@ internal interface IMetadataService : ICastableService /// /// 取消令牌 /// 字典 - ValueTask> GetIdToReliquaryAffixMapAsync(CancellationToken token = default); + ValueTask> GetIdToReliquarySubAffixMapAsync(CancellationToken token = default); /// /// 异步获取圣遗物主词条Id与属性的字典 @@ -211,20 +211,20 @@ internal interface IMetadataService : ICastableService /// /// 取消令牌 /// 等级角色曲线映射 - ValueTask>> GetLevelToAvatarCurveMapAsync(CancellationToken token = default); + ValueTask>> GetLevelToAvatarCurveMapAsync(CancellationToken token = default); /// /// 异步获取等级怪物曲线映射 /// /// 取消令牌 /// 等级怪物曲线映射 - ValueTask>> GetLevelToMonsterCurveMapAsync(CancellationToken token = default); + ValueTask>> GetLevelToMonsterCurveMapAsync(CancellationToken token = default); /// /// 异步获取等级武器曲线映射 /// /// 取消令牌 /// 等级武器曲线映射 - ValueTask>> GetLevelToWeaponCurveMapAsync(CancellationToken token = default); + ValueTask>> GetLevelToWeaponCurveMapAsync(CancellationToken token = default); #endregion } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataOptions.cs b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataOptions.cs index 3afe4e70..9e36b491 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataOptions.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataOptions.cs @@ -84,7 +84,7 @@ internal sealed partial class MetadataOptions : IOptions /// 服务器上的本地化元数据文件 public string GetLocalizedRemoteFile(string fileNameWithExtension) { - return Web.HutaoEndpoints.HutaoMetadataFile(LocaleName, fileNameWithExtension); + return Web.HutaoEndpoints.RawGithubUserContentMetadataFile(LocaleName, fileNameWithExtension); } private string GetLocaleName() diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.Constants.cs b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.Constants.cs new file mode 100644 index 00000000..662ddc54 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.Constants.cs @@ -0,0 +1,33 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +namespace Snap.Hutao.Service.Metadata; + +/// +/// 名称常量 +/// +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"; +} diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.Implementation.cs b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.Implementation.cs index 17c2fe26..c8423955 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.Implementation.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.Implementation.cs @@ -19,84 +19,84 @@ internal sealed partial class MetadataService /// public ValueTask> GetAchievementGoalsAsync(CancellationToken token = default) { - return FromCacheOrFileAsync>("AchievementGoal", token); + return FromCacheOrFileAsync>(FileNameAchievementGoal, token); } /// public ValueTask> GetAchievementsAsync(CancellationToken token = default) { - return FromCacheOrFileAsync>("Achievement", token); + return FromCacheOrFileAsync>(FileNameAchievement, token); } /// public ValueTask> GetAvatarsAsync(CancellationToken token = default) { - return FromCacheOrFileAsync>("Avatar", token); + return FromCacheOrFileAsync>(FileNameAvatar, token); } /// public ValueTask> GetAvatarPromotesAsync(CancellationToken token = default) { - return FromCacheOrFileAsync>("AvatarPromote", token); - } - - /// - public ValueTask> GetWeaponPromotesAsync(CancellationToken token = default) - { - return FromCacheOrFileAsync>("WeaponPromote", token); + return FromCacheOrFileAsync>(FileNameAvatarPromote, token); } /// public ValueTask> GetGachaEventsAsync(CancellationToken token = default) { - return FromCacheOrFileAsync>("GachaEvent2", token); + return FromCacheOrFileAsync>(FileNameGachaEvent, token); } /// public ValueTask> GetMaterialsAsync(CancellationToken token = default) { - return FromCacheOrFileAsync>("Material", token); + return FromCacheOrFileAsync>(FileNameMaterial, token); } /// public ValueTask> GetMonstersAsync(CancellationToken token = default) { - return FromCacheOrFileAsync>("Monster", token); + return FromCacheOrFileAsync>(FileNameMonster, token); } /// public ValueTask> GetReliquariesAsync(CancellationToken token = default) { - return FromCacheOrFileAsync>("Reliquary", token); + return FromCacheOrFileAsync>(FileNameReliquary, token); } /// - public ValueTask> GetReliquaryAffixesAsync(CancellationToken token = default) + public ValueTask> GetReliquaryLevelsAsync(CancellationToken token = default) { - return FromCacheOrFileAsync>("ReliquaryAffix", token); - } - - /// - public ValueTask> GetReliquaryLevelsAsync(CancellationToken token = default) - { - return FromCacheOrFileAsync>("ReliquaryMainAffixLevel", token); + return FromCacheOrFileAsync>(FileNameReliquaryMainAffixLevel, token); } /// public ValueTask> GetReliquaryMainAffixesAsync(CancellationToken token = default) { - return FromCacheOrFileAsync>("ReliquaryMainAffix", token); + return FromCacheOrFileAsync>(FileNameReliquaryMainAffix, token); } /// public ValueTask> GetReliquarySetsAsync(CancellationToken token = default) { - return FromCacheOrFileAsync>("ReliquarySet", token); + return FromCacheOrFileAsync>(FileNameReliquarySet, token); + } + + /// + public ValueTask> GetReliquarySubAffixesAsync(CancellationToken token = default) + { + return FromCacheOrFileAsync>(FileNameReliquarySubAffix, token); } /// public ValueTask> GetWeaponsAsync(CancellationToken token = default) { - return FromCacheOrFileAsync>("Weapon", token); + return FromCacheOrFileAsync>(FileNameWeapon, token); + } + + /// + public ValueTask> GetWeaponPromotesAsync(CancellationToken token = default) + { + return FromCacheOrFileAsync>(FileNameWeaponPromote, token); } } diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.Indexing.cs b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.Indexing.cs index 0ac415ab..f1f6f1e2 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.Indexing.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.Indexing.cs @@ -9,6 +9,7 @@ using Snap.Hutao.Model.Metadata.Item; using Snap.Hutao.Model.Metadata.Reliquary; using Snap.Hutao.Model.Metadata.Weapon; using Snap.Hutao.Model.Primitive; +using System.Runtime.CompilerServices; namespace Snap.Hutao.Service.Metadata; @@ -20,38 +21,38 @@ internal sealed partial class MetadataService /// public ValueTask> GetEquipAffixIdToReliquarySetMapAsync(CancellationToken token = default) { - return FromCacheAsDictionaryAsync("ReliquarySet", r => r.EquipAffixId, token); + return FromCacheAsDictionaryAsync(FileNameReliquarySet, r => r.EquipAffixId, token); } /// public ValueTask> GetIdToAchievementMapAsync(CancellationToken token = default) { - return FromCacheAsDictionaryAsync("Achievement", a => a.Id, token); + return FromCacheAsDictionaryAsync(FileNameAchievement, a => a.Id, token); } /// public ValueTask> GetIdToAvatarMapAsync(CancellationToken token = default) { - return FromCacheAsDictionaryAsync("Avatar", a => a.Id, token); + return FromCacheAsDictionaryAsync(FileNameAvatar, a => a.Id, token); } /// - public async ValueTask> GetIdToDisplayAndMaterialMapAsync(CancellationToken token = default) + public async ValueTask> GetIdToDisplayAndMaterialMapAsync(CancellationToken token = default) { string cacheKey = $"{nameof(MetadataService)}.Cache.DisplayAndMaterial.Map.{typeof(MaterialId).Name}"; if (memoryCache.TryGetValue(cacheKey, out object? value)) { - return Must.NotNull((Dictionary)value!); + return Must.NotNull((Dictionary)value!); } - Dictionary displays = await FromCacheAsDictionaryAsync("Display", a => a.Id, token).ConfigureAwait(false); + Dictionary displays = await FromCacheAsDictionaryAsync(FileNameDisplayItem, a => a.Id, token).ConfigureAwait(false); Dictionary materials = await GetIdToMaterialMapAsync(token).ConfigureAwait(false); // TODO: Cache this - Dictionary results = new(displays); + Dictionary results = new(displays); - foreach ((MaterialId id, Display material) in materials) + foreach ((MaterialId id, DisplayItem material) in materials) { results[id] = material; } @@ -62,54 +63,54 @@ internal sealed partial class MetadataService /// public ValueTask> GetIdToMaterialMapAsync(CancellationToken token = default) { - return FromCacheAsDictionaryAsync("Material", a => a.Id, token); + return FromCacheAsDictionaryAsync(FileNameMaterial, a => a.Id, token); } /// - public ValueTask> GetIdToReliquaryAffixMapAsync(CancellationToken token = default) + public ValueTask> GetIdToReliquarySubAffixMapAsync(CancellationToken token = default) { - return FromCacheAsDictionaryAsync("ReliquaryAffix", a => a.Id, token); + return FromCacheAsDictionaryAsync(FileNameReliquarySubAffix, a => a.Id, token); } /// public ValueTask> GetIdToReliquaryMainPropertyMapAsync(CancellationToken token = default) { - return FromCacheAsDictionaryAsync("ReliquaryMainAffix", r => r.Id, r => r.Type, token); + return FromCacheAsDictionaryAsync(FileNameReliquaryMainAffix, r => r.Id, r => r.Type, token); } /// public ValueTask> GetIdToWeaponMapAsync(CancellationToken token = default) { - return FromCacheAsDictionaryAsync("Weapon", w => w.Id, token); + return FromCacheAsDictionaryAsync(FileNameWeapon, w => w.Id, token); } /// - public ValueTask>> GetLevelToAvatarCurveMapAsync(CancellationToken token = default) + public ValueTask>> GetLevelToAvatarCurveMapAsync(CancellationToken token = default) { - return FromCacheAsDictionaryAsync, GrowCurve>("AvatarCurve", a => a.Level, a => a.Curves, token); + return FromCacheAsDictionaryAsync, GrowCurve>(FileNameAvatarCurve, a => a.Level, a => a.CurveMap, token); } /// - public ValueTask>> GetLevelToMonsterCurveMapAsync(CancellationToken token = default) + public ValueTask>> GetLevelToMonsterCurveMapAsync(CancellationToken token = default) { - return FromCacheAsDictionaryAsync, GrowCurve>("MonsterCurve", m => m.Level, m => m.Curves, token); + return FromCacheAsDictionaryAsync, GrowCurve>(FileNameMonsterCurve, m => m.Level, m => m.CurveMap, token); } /// - public ValueTask>> GetLevelToWeaponCurveMapAsync(CancellationToken token = default) + public ValueTask>> GetLevelToWeaponCurveMapAsync(CancellationToken token = default) { - return FromCacheAsDictionaryAsync, GrowCurve>("WeaponCurve", w => w.Level, w => w.Curves, token); + return FromCacheAsDictionaryAsync, GrowCurve>(FileNameWeaponCurve, w => w.Level, w => w.CurveMap, token); } /// public ValueTask> GetNameToAvatarMapAsync(CancellationToken token = default) { - return FromCacheAsDictionaryAsync("Avatar", a => a.Name, token); + return FromCacheAsDictionaryAsync(FileNameAvatar, a => a.Name, token); } /// public ValueTask> GetNameToWeaponMapAsync(CancellationToken token = default) { - return FromCacheAsDictionaryAsync("Weapon", w => w.Name, token); + return FromCacheAsDictionaryAsync(FileNameWeapon, w => w.Name, token); } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.cs index 3b7f0b46..f06b1d65 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.cs @@ -6,7 +6,7 @@ using Snap.Hutao.Core; using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient; using Snap.Hutao.Core.Diagnostics; using Snap.Hutao.Core.ExceptionService; -using Snap.Hutao.Core.IO; +using Snap.Hutao.Core.IO.Hashing; using Snap.Hutao.Service.Notification; using System.IO; using System.Net.Http; @@ -122,12 +122,12 @@ internal sealed partial class MetadataService : IMetadataService, IMetadataServi string fileFullPath = metadataOptions.GetLocalizedLocalFile(fileFullName); if (File.Exists(fileFullPath)) { - skip = md5 == await Digest.GetFileMD5Async(fileFullPath, token).ConfigureAwait(false); + skip = md5 == await XXH64.HashFileAsync(fileFullPath, token).ConfigureAwait(false); } 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); } @@ -182,6 +182,7 @@ internal sealed partial class MetadataService : IMetadataService, IMetadataServi } else { + FileNotFoundException exception = new(SH.ServiceMetadataFileNotFound, fileName); throw ThrowHelper.UserdataCorrupted(SH.ServiceMetadataFileNotFound, null!); } } diff --git a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj index 565ba4f7..0a198dd6 100644 --- a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj +++ b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj @@ -253,7 +253,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -268,6 +268,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/Snap.Hutao/Snap.Hutao/View/Control/ItemIcon.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Control/ItemIcon.xaml.cs index 0e29cf2b..41ee5d44 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Control/ItemIcon.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/View/Control/ItemIcon.xaml.cs @@ -14,7 +14,7 @@ namespace Snap.Hutao.View.Control; [HighQuality] internal sealed partial class ItemIcon : UserControl { - private static readonly DependencyProperty QualityProperty = Property.Depend(nameof(Quality), ItemQuality.QUALITY_NONE); + private static readonly DependencyProperty QualityProperty = Property.Depend(nameof(Quality), QualityType.QUALITY_NONE); private static readonly DependencyProperty IconProperty = Property.Depend(nameof(Icon)); private static readonly DependencyProperty BadgeProperty = Property.Depend(nameof(Badge)); @@ -29,9 +29,9 @@ internal sealed partial class ItemIcon : UserControl /// /// 等阶 /// - public ItemQuality Quality + public QualityType Quality { - get => (ItemQuality)GetValue(QualityProperty); + get => (QualityType)GetValue(QualityProperty); set => SetValue(QualityProperty, value); } diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/WikiAvatarPage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/WikiAvatarPage.xaml index f36c911f..27c31222 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/WikiAvatarPage.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/WikiAvatarPage.xaml @@ -521,7 +521,7 @@ Width="80" Height="80" Margin="0,0,16,0" - Source="{Binding Icon, Converter={StaticResource AvatarCardConverter}}"/> + Source="{Binding FrontIcon, Converter={StaticResource AvatarCardConverter}}"/> /// 排序顺序 /// - public int Order { get; } + public uint Order { get; } /// /// 名称 diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/AvatarProperty/AvatarView.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/AvatarProperty/AvatarView.cs index 97ebfdb2..4432dc38 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/AvatarProperty/AvatarView.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/AvatarProperty/AvatarView.cs @@ -36,7 +36,7 @@ internal sealed class AvatarView : INameIconSide, ICalculableSource /// 星级 /// - public ItemQuality Quality { get; set; } + public QualityType Quality { get; set; } /// /// 元素类型 @@ -91,7 +91,7 @@ internal sealed class AvatarView : INameIconSide, ICalculableSource /// 好感度等级 /// - public int FetterLevel { get; set; } + public uint FetterLevel { get; set; } /// /// Id @@ -101,7 +101,7 @@ internal sealed class AvatarView : INameIconSide, ICalculableSource /// 等级数字 /// - internal int LevelNumber { get; set; } + internal uint LevelNumber { get; set; } /// public ICalculableAvatar ToCalculable() diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/AvatarProperty/Equip.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/AvatarProperty/Equip.cs index f55ccdc8..e797f7db 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/AvatarProperty/Equip.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/AvatarProperty/Equip.cs @@ -20,7 +20,7 @@ internal abstract class Equip : NameIconDescription /// /// 品质 /// - public ItemQuality Quality { get; set; } + public QualityType Quality { get; set; } /// /// 主属性 diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/AvatarProperty/SkillView.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/AvatarProperty/SkillView.cs index 19c73b39..5a6e899b 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/AvatarProperty/SkillView.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/AvatarProperty/SkillView.cs @@ -3,6 +3,7 @@ using Snap.Hutao.Model.Calculable; using Snap.Hutao.Model.Metadata; +using Snap.Hutao.Model.Primitive; namespace Snap.Hutao.ViewModel.AvatarProperty; @@ -20,7 +21,7 @@ internal sealed class SkillView : NameIconDescription, ICalculableSource /// 不计算命座的技能等级 /// - public int LevelNumber { get; set; } + public uint LevelNumber { get; set; } /// /// 不计算命座的技能等级字符串 @@ -30,7 +31,7 @@ internal sealed class SkillView : NameIconDescription, ICalculableSource /// 技能组Id /// - internal int GroupId { get; set; } + internal SkillGroupId GroupId { get; set; } /// public ICalculableSkill ToCalculable() diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/AvatarProperty/WeaponView.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/AvatarProperty/WeaponView.cs index 6374a0f1..f7225181 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/AvatarProperty/WeaponView.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/AvatarProperty/WeaponView.cs @@ -20,7 +20,7 @@ internal sealed class WeaponView : Equip, ICalculableSource /// /// 精炼等级 /// - public int AffixLevelNumber { get; set; } + public uint AffixLevelNumber { get; set; } /// /// 精炼属性 @@ -45,12 +45,12 @@ internal sealed class WeaponView : Equip, ICalculableSource /// /// 等级数字 /// - internal int LevelNumber { get; set; } + internal uint LevelNumber { get; set; } /// /// 最大等级 /// - internal int MaxLevel { get => ((int)Quality) >= 3 ? 90 : 70; } + internal uint MaxLevel { get => ((int)Quality) >= 3 ? 90U : 70U; } /// public ICalculableWeapon ToCalculable() diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/AvatarView.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/AvatarView.cs index 95eff5e3..433541ba 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/AvatarView.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/AvatarView.cs @@ -46,7 +46,7 @@ internal class AvatarView : INameIconSide /// /// 星级 /// - public ItemQuality Quality { get; } + public QualityType Quality { get; } /// /// 比率 diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/Team.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/Team.cs index eb60033d..56b267c7 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/Team.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/Team.cs @@ -24,7 +24,7 @@ internal sealed class Team : List { foreach (StringSegment item in new StringTokenizer(team.Item, new char[] { ',' })) { - int id = int.Parse(item.AsSpan()); + uint id = uint.Parse(item.AsSpan()); Add(new(idAvatarMap[id], 0)); } diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/WeaponView.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/WeaponView.cs index 9bae0908..8b7956dd 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/WeaponView.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Complex/WeaponView.cs @@ -40,7 +40,7 @@ internal sealed class WeaponView : INameIcon /// /// 星级 /// - public ItemQuality Quality { get; } + public QualityType Quality { get; } /// /// 比率 diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Cultivation/CultivateEntryView.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Cultivation/CultivateEntryView.cs index 71cc5ced..78f3fd97 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Cultivation/CultivateEntryView.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Cultivation/CultivateEntryView.cs @@ -31,7 +31,7 @@ internal sealed class CultivateEntryView : Item /// /// Id /// - public int Id { get; set; } + public uint Id { get; set; } /// /// 入口Id diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLog/GachaLogViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLog/GachaLogViewModel.cs index 8860c25c..ca019ffd 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLog/GachaLogViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/GachaLog/GachaLogViewModel.cs @@ -350,10 +350,11 @@ internal sealed partial class GachaLogViewModel : Abstraction.ViewModel // ContentDialog must be created by main thread. await taskContext.SwitchToMainThreadAsync(); GachaLogImportDialog importDialog = serviceProvider.CreateInstance(uigf); - if (await importDialog.GetShouldImportAsync().ConfigureAwait(true)) + if (await importDialog.GetShouldImportAsync().ConfigureAwait(false)) { if (CanImport(version, uigf)) { + await taskContext.SwitchToMainThreadAsync(); ContentDialog dialog = await contentDialogFactory.CreateForIndeterminateProgressAsync(SH.ViewModelGachaLogImportProgress).ConfigureAwait(true); using (await dialog.BlockAsync(taskContext).ConfigureAwait(false)) { diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/SpiralAbyss/AvatarView.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/SpiralAbyss/AvatarView.cs index b8f4f718..8f748b76 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/SpiralAbyss/AvatarView.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/SpiralAbyss/AvatarView.cs @@ -53,5 +53,5 @@ internal class AvatarView : INameIconSide /// /// 星级 /// - public ItemQuality Quality { get; } + public QualityType Quality { get; } } diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/SpiralAbyss/LevelView.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/SpiralAbyss/LevelView.cs index 7bfe4b77..8f7dbde2 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/SpiralAbyss/LevelView.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/SpiralAbyss/LevelView.cs @@ -2,7 +2,6 @@ // Licensed under the MIT license. using Snap.Hutao.Model.Primitive; -using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.SpiralAbyss; namespace Snap.Hutao.ViewModel.SpiralAbyss; @@ -17,7 +16,7 @@ internal sealed class LevelView /// /// 间 /// Id角色映射 - public LevelView(Level level, Dictionary idAvatarMap) + public LevelView(Web.Hoyolab.Takumi.GameRecord.SpiralAbyss.Level level, Dictionary idAvatarMap) { Index = string.Format(SH.ModelBindingHutaoComplexRankLevel, level.Index); Star = level.Star; diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/BaseValueInfo.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/BaseValueInfo.cs index 724ba27e..19b5bc04 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/BaseValueInfo.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/BaseValueInfo.cs @@ -6,6 +6,7 @@ using Snap.Hutao.Model; using Snap.Hutao.Model.Intrinsic; using Snap.Hutao.Model.Metadata; using Snap.Hutao.Model.Metadata.Converter; +using Snap.Hutao.Model.Primitive; namespace Snap.Hutao.ViewModel.Wiki; @@ -15,10 +16,10 @@ namespace Snap.Hutao.ViewModel.Wiki; internal sealed class BaseValueInfo : ObservableObject { private readonly List propValues; - private readonly Dictionary> growCurveMap; - private readonly Dictionary? promoteMap; + private readonly Dictionary> growCurveMap; + private readonly Dictionary? promoteMap; - private int currentLevel; + private uint currentLevel; private List> values = default!; private bool promoted = true; @@ -29,7 +30,7 @@ internal sealed class BaseValueInfo : ObservableObject /// 属性与初始值 /// 生长曲线 /// 突破加成 - public BaseValueInfo(int maxLevel, List propValues, Dictionary> growCurveMap, Dictionary? promoteMap = null) + public BaseValueInfo(uint maxLevel, List propValues, Dictionary> growCurveMap, Dictionary? promoteMap = null) { this.propValues = propValues; this.growCurveMap = growCurveMap; @@ -42,7 +43,7 @@ internal sealed class BaseValueInfo : ObservableObject /// /// 最大等级 /// - public int MaxLevel { get; } + public uint MaxLevel { get; } /// /// 对应的基础值 @@ -52,7 +53,7 @@ internal sealed class BaseValueInfo : ObservableObject /// /// 当前等级 /// - public int CurrentLevel + public uint CurrentLevel { get => currentLevel; set @@ -88,15 +89,16 @@ internal sealed class BaseValueInfo : ObservableObject } } - private void UpdateValues(int level, bool promoted) + [SuppressMessage("", "SH002")] + private void UpdateValues(Level level, bool promoted) { Values = propValues.SelectList(propValue => { float value = propValue.Value * growCurveMap[level].GetValueOrDefault(propValue.Type); if (promoteMap != null) { - int promoteLevel = GetPromoteLevel(level, promoted); - float addValue = promoteMap[promoteLevel].AddProperties.GetValueOrDefault(propValue.Property, 0F); + PromoteLevel promoteLevel = GetPromoteLevel(level, promoted); + float addValue = promoteMap[promoteLevel].AddPropertyMap.GetValueOrDefault(propValue.Property, 0F); value += addValue; } @@ -105,29 +107,29 @@ internal sealed class BaseValueInfo : ObservableObject }); } - private int GetPromoteLevel(int level, bool promoted) + private PromoteLevel GetPromoteLevel(in Level level, bool promoted) { if (MaxLevel <= 70) { if (promoted) { - return level switch + return level.Value switch { - >= 60 => 4, - >= 50 => 3, - >= 40 => 2, - >= 20 => 1, + >= 60U => 4, + >= 50U => 3, + >= 40U => 2, + >= 20U => 1, _ => 0, }; } else { - return level switch + return level.Value switch { - > 60 => 4, - > 50 => 3, - > 40 => 2, - > 20 => 1, + > 60U => 4, + > 50U => 3, + > 40U => 2, + > 20U => 1, _ => 0, }; } @@ -136,27 +138,27 @@ internal sealed class BaseValueInfo : ObservableObject { if (promoted) { - return level switch + return level.Value switch { - >= 80 => 6, - >= 70 => 5, - >= 60 => 4, - >= 50 => 3, - >= 40 => 2, - >= 20 => 1, + >= 80U => 6, + >= 70U => 5, + >= 60U => 4, + >= 50U => 3, + >= 40U => 2, + >= 20U => 1, _ => 0, }; } else { - return level switch + return level.Value switch { - > 80 => 6, - > 70 => 5, - > 60 => 4, - > 50 => 3, - > 40 => 2, - > 20 => 1, + > 80U => 6, + > 70U => 5, + > 60U => 4, + > 50U => 3, + > 40U => 2, + > 20U => 1, _ => 0, }; } diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WeaponFilter.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WeaponFilter.cs index 7d079239..75745da1 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WeaponFilter.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WeaponFilter.cs @@ -50,7 +50,7 @@ internal static class WeaponFilter if (IntrinsicImmutables.FightProperties.Contains(value)) { - matches.Add(weapon.GrowCurves.ElementAtOrDefault(1).Key.GetLocalizedDescriptionOrDefault() == value); + matches.Add(weapon.GrowCurves.ElementAtOrDefault(1)?.Type.GetLocalizedDescriptionOrDefault() == value); continue; } } diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiAvatarViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiAvatarViewModel.cs index f89b67c4..2e4df383 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiAvatarViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiAvatarViewModel.cs @@ -46,7 +46,7 @@ internal sealed partial class WikiAvatarViewModel : Abstraction.ViewModel private Avatar? selected; private string? filterText; private BaseValueInfo? baseValueInfo; - private Dictionary>? levelAvatarCurveMap; + private Dictionary>? levelAvatarCurveMap; private List? promotes; /// @@ -182,15 +182,15 @@ internal sealed partial class WikiAvatarViewModel : Abstraction.ViewModel } else { - Dictionary avatarPromoteMap = promotes!.Where(p => p.Id == avatar.PromoteId).ToDictionary(p => p.Level); - - FightProperty promoteProperty = avatarPromoteMap[0].AddProperties.Keys.Last(); + Dictionary avatarPromoteMap = promotes!.Where(p => p.Id == avatar.PromoteId).ToDictionary(p => p.Level); + Dictionary avatarGrowCurve = avatar.GrowCurves.ToDictionary(g => g.Type, g => g.Value); + FightProperty promoteProperty = avatarPromoteMap[0].AddProperties.Last().Type; List propertyCurveValues = new() { - new(FightProperty.FIGHT_PROP_BASE_HP, avatar.GrowCurves[FightProperty.FIGHT_PROP_BASE_HP], avatar.BaseValue.HpBase), - new(FightProperty.FIGHT_PROP_BASE_ATTACK, avatar.GrowCurves[FightProperty.FIGHT_PROP_BASE_ATTACK], avatar.BaseValue.AttackBase), - new(FightProperty.FIGHT_PROP_BASE_DEFENSE, avatar.GrowCurves[FightProperty.FIGHT_PROP_BASE_DEFENSE], avatar.BaseValue.DefenseBase), + new(FightProperty.FIGHT_PROP_BASE_HP, avatarGrowCurve[FightProperty.FIGHT_PROP_BASE_HP], avatar.BaseValue.HpBase), + new(FightProperty.FIGHT_PROP_BASE_ATTACK, avatarGrowCurve[FightProperty.FIGHT_PROP_BASE_ATTACK], avatar.BaseValue.AttackBase), + new(FightProperty.FIGHT_PROP_BASE_DEFENSE, avatarGrowCurve[FightProperty.FIGHT_PROP_BASE_DEFENSE], avatar.BaseValue.DefenseBase), new(promoteProperty, GrowCurveType.GROW_CURVE_NONE, 0), }; diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiMonsterViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiMonsterViewModel.cs index e0cc1629..bae18d11 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiMonsterViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiMonsterViewModel.cs @@ -24,7 +24,7 @@ internal sealed partial class WikiMonsterViewModel : Abstraction.ViewModel private AdvancedCollectionView? monsters; private Monster? selected; private BaseValueInfo? baseValueInfo; - private Dictionary>? levelMonsterCurveMap; + private Dictionary>? levelMonsterCurveMap; /// /// 角色列表 @@ -58,7 +58,7 @@ internal sealed partial class WikiMonsterViewModel : Abstraction.ViewModel levelMonsterCurveMap = await metadataService.GetLevelToMonsterCurveMapAsync().ConfigureAwait(false); List monsters = await metadataService.GetMonstersAsync().ConfigureAwait(false); - Dictionary idDisplayMap = await metadataService.GetIdToDisplayAndMaterialMapAsync().ConfigureAwait(false); + Dictionary idDisplayMap = await metadataService.GetIdToDisplayAndMaterialMapAsync().ConfigureAwait(false); foreach (Monster monster in monsters) { monster.DropsView ??= monster.Drops?.SelectList(i => idDisplayMap.GetValueOrDefault(i)!); @@ -81,7 +81,7 @@ internal sealed partial class WikiMonsterViewModel : Abstraction.ViewModel else { List propertyCurveValues = monster.GrowCurves - .Select(curveInfo => new PropertyCurveValue(curveInfo.Key, curveInfo.Value, monster.BaseValue.GetValue(curveInfo.Key))) + .Select(curveInfo => new PropertyCurveValue(curveInfo.Type, curveInfo.Value, monster.BaseValue.GetValue(curveInfo.Type))) .ToList(); BaseValueInfo = new(100, propertyCurveValues, levelMonsterCurveMap!); diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiWeaponViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiWeaponViewModel.cs index 937bcab9..abe6ba8f 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiWeaponViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Wiki/WikiWeaponViewModel.cs @@ -46,7 +46,7 @@ internal sealed partial class WikiWeaponViewModel : Abstraction.ViewModel private Weapon? selected; private string? filterText; private BaseValueInfo? baseValueInfo; - private Dictionary>? levelWeaponCurveMap; + private Dictionary>? levelWeaponCurveMap; private List? promotes; /// @@ -177,10 +177,10 @@ internal sealed partial class WikiWeaponViewModel : Abstraction.ViewModel } else { - Dictionary weaponPromoteMap = promotes!.Where(p => p.Id == weapon.PromoteId).ToDictionary(p => p.Level); + Dictionary weaponPromoteMap = promotes!.Where(p => p.Id == weapon.PromoteId).ToDictionary(p => p.Level); List propertyCurveValues = weapon.GrowCurves - .Select(curveInfo => new PropertyCurveValue(curveInfo.Key, curveInfo.Value.Type, curveInfo.Value.Value)) + .Select(curveInfo => new PropertyCurveValue(curveInfo.Type, curveInfo.Value, curveInfo.InitValue)) .ToList(); BaseValueInfo = new(weapon.MaxLevel, propertyCurveValues, levelWeaponCurveMap!, weaponPromoteMap); diff --git a/src/Snap.Hutao/Snap.Hutao/Web/ApiEndpoints.cs b/src/Snap.Hutao/Snap.Hutao/Web/ApiEndpoints.cs index 6bb9da32..e6cb482f 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/ApiEndpoints.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/ApiEndpoints.cs @@ -101,6 +101,11 @@ internal static class ApiEndpoints /// public const string CardWidgetData = $"{ApiTakumiCardApi}/getWidgetData?game_id=2"; + /// + /// 小组件数据v2 + /// + public const string CardWidgetData2 = $"{ApiTakumiRecordAapi}/widget/v2?game_id=2"; + /// /// 发起验证码 /// @@ -346,6 +351,7 @@ internal static class ApiEndpoints private const string ApiTakumiRecord = "https://api-takumi-record.mihoyo.com"; private const string ApiTakumiRecordApi = $"{ApiTakumiRecord}/game_record/app/genshin/api"; + private const string ApiTakumiRecordAapi = $"{ApiTakumiRecord}/game_record/app/genshin/aapi"; /// /// Referer: https://app.mihoyo.com diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/AvatarInfo.cs b/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/AvatarInfo.cs index d867cba9..b5f8ac2d 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/AvatarInfo.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/AvatarInfo.cs @@ -52,13 +52,13 @@ internal sealed class AvatarInfo /// 被动天赋 /// [JsonPropertyName("inherentProudSkillList")] - public List InherentProudSkillList { get; set; } = default!; + public List InherentProudSkillList { get; set; } = default!; /// /// Map of Skill Levels /// [JsonPropertyName("skillLevelMap")] - public Dictionary SkillLevelMap { get; set; } = default!; + public Dictionary SkillLevelMap { get; set; } = default!; /// /// 装备列表 @@ -85,5 +85,5 @@ internal sealed class AvatarInfo /// 命座额外技能等级 /// [JsonPropertyName("proudSkillExtraLevelMap")] - public Dictionary? ProudSkillExtraLevelMap { get; set; } = default!; + public Dictionary? ProudSkillExtraLevelMap { get; set; } = default!; } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/EnkaResponse.cs b/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/EnkaResponse.cs index 8f331f66..7c99346a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/EnkaResponse.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/EnkaResponse.cs @@ -19,14 +19,14 @@ internal sealed class EnkaResponse /// 展示的角色详细信息列表 /// [JsonPropertyName("avatarInfoList")] - public IList? AvatarInfoList { get; set; } = default!; + public List? AvatarInfoList { get; set; } = default!; /// /// 刷新剩余秒数 /// 生存时间值 /// [JsonPropertyName("ttl")] - public int? Ttl { get; set; } + public int? TimeToLive { get; set; } /// /// 此响应是否有效 diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/Equip.cs b/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/Equip.cs index 8e363dde..b61741d2 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/Equip.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/Equip.cs @@ -14,7 +14,7 @@ internal sealed class Equip /// Equipment ID /// [JsonPropertyName("itemId")] - public int ItemId { get; set; } + public uint ItemId { get; set; } /// /// 圣遗物 diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/FetterInfo.cs b/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/FetterInfo.cs index 637e96c8..e3858b9b 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/FetterInfo.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/FetterInfo.cs @@ -1,6 +1,8 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using Snap.Hutao.Model.Primitive; + namespace Snap.Hutao.Web.Enka.Model; /// @@ -13,5 +15,5 @@ internal sealed class FetterInfo /// 好感度等级 /// [JsonPropertyName("expLevel")] - public int ExpLevel { get; set; } + public FetterLevel ExpLevel { get; set; } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/Flat.cs b/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/Flat.cs index 4049eb1e..40bec224 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/Flat.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/Flat.cs @@ -1,6 +1,7 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using Snap.Hutao.Core.Json.Annotation; using Snap.Hutao.Model.Intrinsic; namespace Snap.Hutao.Web.Enka.Model; @@ -16,21 +17,21 @@ internal sealed class Flat /// Hash for Equipment Name /// [JsonPropertyName("nameTextMapHash")] - public string NameTextMapHash { get; set; } = default!; + public ulong NameTextMapHash { get; set; } /// /// 套装名称 /// Hash for Artifact Set Name /// [JsonPropertyName("setNameTextMapHash")] - public string? SetNameTextMapHash { get; set; } + public ulong SetNameTextMapHash { get; set; } /// /// 等级 /// Rarity Level of Equipment /// [JsonPropertyName("rankLevel")] - public int RankLevel { get; set; } + public QualityType RankLevel { get; set; } /// /// 圣遗物主属性 @@ -53,7 +54,7 @@ internal sealed class Flat /// ITEM_RELIQUARY /// [JsonPropertyName("itemType")] - [JsonConverter(typeof(JsonStringEnumConverter))] + [JsonEnum(JsonSerializeType.String)] public ItemType ItemType { get; set; } = default!; /// @@ -69,7 +70,7 @@ internal sealed class Flat /// 值为 /// [JsonPropertyName("equipType")] - [JsonConverter(typeof(JsonStringEnumConverter))] + [JsonEnum(JsonSerializeType.String)] public EquipType EquipType { get; set; } /// diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/PlayerInfo.cs b/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/PlayerInfo.cs index 2095bd98..b58afd71 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/PlayerInfo.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/PlayerInfo.cs @@ -20,7 +20,7 @@ internal sealed class PlayerInfo /// 等级 /// [JsonPropertyName("level")] - public int Level { get; set; } + public uint Level { get; set; } /// /// 签名 @@ -34,42 +34,42 @@ internal sealed class PlayerInfo /// Player World Level /// [JsonPropertyName("worldLevel")] - public int WorldLevel { get; set; } + public uint WorldLevel { get; set; } /// /// 名片的Id /// Profile Namecard ID /// [JsonPropertyName("nameCardId")] - public int NameCardId { get; set; } + public uint NameCardId { get; set; } /// /// 完成的成就个数 /// Number of Completed Achievements /// [JsonPropertyName("finishAchievementNum")] - public int FinishAchievementNum { get; set; } + public uint FinishAchievementNum { get; set; } /// /// 深渊层数 /// Abyss Floor /// [JsonPropertyName("towerFloorIndex")] - public int TowerFloorIndex { get; set; } + public uint TowerFloorIndex { get; set; } /// /// 深渊间数 /// Abyss Floor's Level /// [JsonPropertyName("towerLevelIndex")] - public int TowerLevelIndex { get; set; } + public uint TowerLevelIndex { get; set; } /// /// 展示的角色信息 /// List of Character IDs and Levels /// [JsonPropertyName("showAvatarInfoList")] - public IList ShowAvatarInfoList { get; set; } = default!; + public List ShowAvatarInfoList { get; set; } = default!; /// /// 展示的名片信息 @@ -84,4 +84,4 @@ internal sealed class PlayerInfo /// [JsonPropertyName("profilePicture")] public ProfilePicture ProfilePicture { get; set; } = default!; -} +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/ProfilePicture.cs b/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/ProfilePicture.cs index d7d90b28..c37aabe5 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/ProfilePicture.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/ProfilePicture.cs @@ -1,6 +1,8 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using Snap.Hutao.Model.Primitive; + namespace Snap.Hutao.Web.Enka.Model; /// @@ -13,11 +15,11 @@ internal sealed class ProfilePicture /// 使用的角色Id /// [JsonPropertyName("avatarId")] - public int AvatarId { get; set; } + public AvatarId AvatarId { get; set; } /// /// 衣装Id /// [JsonPropertyName("costumeId")] - public int? CostumeId { get; set; } + public CostumeId? CostumeId { get; set; } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/Reliquary.cs b/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/Reliquary.cs index 5f7a1060..28b0936b 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/Reliquary.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/Reliquary.cs @@ -1,6 +1,8 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using Snap.Hutao.Model.Primitive; + namespace Snap.Hutao.Web.Enka.Model; /// @@ -11,22 +13,22 @@ internal sealed class Reliquary { /// /// 等级 +20 = 21 - /// [1,21] + /// [1-21] /// Artifact Level [1-21] /// [JsonPropertyName("level")] - public int Level { get; set; } + public ReliquaryLevel Level { get; set; } /// /// 主属性Id /// Artifact Main Stat ID /// [JsonPropertyName("mainPropId")] - public int MainPropId { get; set; } + public ReliquaryMainAffixId MainPropId { get; set; } /// /// 强化属性Id /// [JsonPropertyName("appendPropIdList")] - public List AppendPropIdList { get; set; } = default!; + public List AppendPropIdList { get; set; } = default!; } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/ReliquaryMainstat.cs b/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/ReliquaryMainstat.cs index c7b423d5..70a1428a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/ReliquaryMainstat.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/ReliquaryMainstat.cs @@ -10,7 +10,7 @@ namespace Snap.Hutao.Web.Enka.Model; /// 圣遗物主属性 /// [HighQuality] -internal sealed class ReliquaryMainstat +internal sealed class ReliquaryMainstat : Stat { /// /// Equipment Append Property Name. @@ -18,10 +18,4 @@ internal sealed class ReliquaryMainstat [JsonPropertyName("mainPropId")] [JsonEnum(JsonSerializeType.String)] public FightProperty MainPropId { get; set; } - - /// - /// Property Value - /// - [JsonPropertyName("statValue")] - public double StatValue { get; set; } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/ReliquarySubstat.cs b/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/ReliquarySubstat.cs index a827df1f..a71a44f0 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/ReliquarySubstat.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/ReliquarySubstat.cs @@ -10,7 +10,7 @@ namespace Snap.Hutao.Web.Enka.Model; /// 圣遗物副属性 /// [HighQuality] -internal sealed class ReliquarySubstat +internal class ReliquarySubstat : Stat { /// /// 增加属性 @@ -18,10 +18,4 @@ internal sealed class ReliquarySubstat [JsonPropertyName("appendPropId")] [JsonEnum(JsonSerializeType.String)] public FightProperty AppendPropId { get; set; } - - /// - /// 值 - /// - [JsonPropertyName("statValue")] - public double StatValue { get; set; } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/ShowAvatarInfo.cs b/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/ShowAvatarInfo.cs index 724928ca..07d6a38e 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/ShowAvatarInfo.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/ShowAvatarInfo.cs @@ -1,6 +1,8 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using Snap.Hutao.Model.Primitive; + namespace Snap.Hutao.Web.Enka.Model; /// @@ -14,18 +16,18 @@ internal sealed class ShowAvatarInfo /// Character ID /// [JsonPropertyName("avatarId")] - public int AvatarId { get; set; } + public AvatarId AvatarId { get; set; } /// /// 角色等级 /// Character Level /// [JsonPropertyName("level")] - public int Level { get; set; } + public Level Level { get; set; } /// /// 可能的皮肤Id /// [JsonPropertyName("costumeId")] - public int? CostumeId { get; set; } + public CostumeId? CostumeId { get; set; } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/Stat.cs b/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/Stat.cs new file mode 100644 index 00000000..04cd5fa3 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/Stat.cs @@ -0,0 +1,17 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +namespace Snap.Hutao.Web.Enka.Model; + +/// +/// 圣遗物属性值 +/// +internal abstract class Stat +{ + /// + /// 属性值 + /// Property Value + /// + [JsonPropertyName("statValue")] + public float StatValue { get; set; } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/TypeValue.cs b/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/TypeValue.cs index d0fb21d6..9d0c95b9 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/TypeValue.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/TypeValue.cs @@ -7,6 +7,7 @@ namespace Snap.Hutao.Web.Enka.Model; /// /// 类型与值 +/// 与元数据的 TypeValue 不同! /// [HighQuality] internal sealed class TypeValue @@ -24,7 +25,7 @@ internal sealed class TypeValue /// /// 类型 /// 值 - public TypeValue(PlayerProperty type, int value) + public TypeValue(PlayerProperty type, uint value) { Type = type; Value = value; @@ -40,6 +41,5 @@ internal sealed class TypeValue /// 值 /// [JsonPropertyName("val")] - [JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)] - public int Value { get; set; } + public uint Value { get; set; } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/Weapon.cs b/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/Weapon.cs index b941ecf6..42f6e2db 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/Weapon.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/Weapon.cs @@ -1,6 +1,8 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using Snap.Hutao.Model.Primitive; + namespace Snap.Hutao.Web.Enka.Model; /// @@ -14,19 +16,19 @@ internal sealed class Weapon /// Weapon Level /// [JsonPropertyName("level")] - public int Level { get; set; } + public Level Level { get; set; } /// /// 突破等级 /// Weapon Ascension Level /// [JsonPropertyName("promoteLevel")] - public int PromoteLevel { get; set; } + public Level PromoteLevel { get; set; } /// /// 精炼 相较于实际等级 -1 /// Weapon Refinement Level [0-4] /// [JsonPropertyName("affixMap")] - public Dictionary AffixMap { get; set; } = default!; + public Dictionary AffixMap { get; set; } = default!; } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/WeaponStat.cs b/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/WeaponStat.cs index 840f19da..a916087d 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/WeaponStat.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Enka/Model/WeaponStat.cs @@ -1,26 +1,11 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. -using Snap.Hutao.Core.Json.Annotation; -using Snap.Hutao.Model.Intrinsic; - namespace Snap.Hutao.Web.Enka.Model; /// /// 武器属性 /// -internal sealed class WeaponStat +internal sealed class WeaponStat : ReliquarySubstat { - /// - /// 提升属性Id - /// - [JsonPropertyName("appendPropId")] - [JsonEnum(JsonSerializeType.String)] - public FightProperty AppendPropId { get; set; } - - /// - /// 值 - /// - [JsonPropertyName("statValue")] - public float StatValue { get; set; } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/DynamicSecret/HttpClientDynamicSecretExtensions.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/DynamicSecret/HttpClientDynamicSecretExtension.cs similarity index 93% rename from src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/DynamicSecret/HttpClientDynamicSecretExtensions.cs rename to src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/DynamicSecret/HttpClientDynamicSecretExtension.cs index 6fcb149e..692d9f2a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/DynamicSecret/HttpClientDynamicSecretExtensions.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/DynamicSecret/HttpClientDynamicSecretExtension.cs @@ -10,7 +10,7 @@ namespace Snap.Hutao.Web.Hoyolab.DynamicSecret; /// 动态密钥扩展 /// [HighQuality] -internal static class HttpClientDynamicSecretExtensions +internal static class HttpClientDynamicSecretExtension { /// /// 使用动态密钥 diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Event/GachaInfo/GachaLogItem.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Event/GachaInfo/GachaLogItem.cs index 85145295..ee0a60bf 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Event/GachaInfo/GachaLogItem.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Event/GachaInfo/GachaLogItem.cs @@ -69,7 +69,7 @@ internal class GachaLogItem /// [JsonPropertyName("rank_type")] [JsonEnum(JsonSerializeType.NumberString)] - public ItemQuality Rank { get; set; } = default!; + public QualityType Rank { get; set; } = default!; /// /// Id diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/SdkStatic/Hk4e/Launcher/Package.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/SdkStatic/Hk4e/Launcher/Package.cs index bf9cc75a..821e67f5 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/SdkStatic/Hk4e/Launcher/Package.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/SdkStatic/Hk4e/Launcher/Package.cs @@ -25,7 +25,6 @@ internal class Package : PathMd5 /// 尺寸 /// [JsonPropertyName("size")] - [JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)] public long Size { get; set; } = default!; /// @@ -52,6 +51,5 @@ internal class Package : PathMd5 /// 包大小 bytes /// [JsonPropertyName("package_size")] - [JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)] public long PackageSize { get; set; } = default!; } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/SdkStatic/Hk4e/Launcher/PluginItem.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/SdkStatic/Hk4e/Launcher/PluginItem.cs index 67b0a00a..52f14be5 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/SdkStatic/Hk4e/Launcher/PluginItem.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/SdkStatic/Hk4e/Launcher/PluginItem.cs @@ -25,7 +25,6 @@ internal sealed class PluginItem : NameMd5 /// 尺寸 /// [JsonPropertyName("size")] - [JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)] public long Size { get; set; } = default!; /// diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/SdkStatic/Hk4e/Launcher/VoicePackage.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/SdkStatic/Hk4e/Launcher/VoicePackage.cs index 0dcaf831..5329b291 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/SdkStatic/Hk4e/Launcher/VoicePackage.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/SdkStatic/Hk4e/Launcher/VoicePackage.cs @@ -25,13 +25,11 @@ internal sealed class VoicePackage : PathMd5 /// 解压尺寸 /// [JsonPropertyName("size")] - [JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)] public long Size { get; set; } /// /// 包尺寸 /// [JsonPropertyName("package_size")] - [JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)] public long PackageSize { get; set; } = default!; } diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Event/Calculate/Avatar.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Event/Calculate/Avatar.cs index 0f84ac09..de399c11 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Event/Calculate/Avatar.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Event/Calculate/Avatar.cs @@ -15,7 +15,7 @@ internal sealed class Avatar : Calculable /// 角色的星级 /// [JsonPropertyName("avatar_level")] - public ItemQuality AvatarLevel { get; set; } + public QualityType AvatarLevel { get; set; } /// /// 武器类型 diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Event/Calculate/AvatarPromotionDelta.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Event/Calculate/AvatarPromotionDelta.cs index b8a4d0a2..5fb04134 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Event/Calculate/AvatarPromotionDelta.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Event/Calculate/AvatarPromotionDelta.cs @@ -21,13 +21,13 @@ internal sealed class AvatarPromotionDelta /// 当前角色等级 /// [JsonPropertyName("avatar_level_current")] - public int AvatarLevelCurrent { get; set; } + public uint AvatarLevelCurrent { get; set; } /// /// 目标角色等级 /// [JsonPropertyName("avatar_level_target")] - public int AvatarLevelTarget { get; set; } + public uint AvatarLevelTarget { get; set; } /// /// 元素类型 diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Event/Calculate/Calculable.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Event/Calculate/Calculable.cs index ada77885..411b6c73 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Event/Calculate/Calculable.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Event/Calculate/Calculable.cs @@ -1,6 +1,8 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using Snap.Hutao.Model.Primitive; + namespace Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate; /// @@ -13,7 +15,7 @@ internal class Calculable /// Id /// [JsonPropertyName("id")] - public int Id { get; set; } + public uint Id { get; set; } /// /// 名称 @@ -31,7 +33,7 @@ internal class Calculable /// 默认值设为1,因为部分API不返回该字段 /// [JsonPropertyName("level_current")] - public int LevelCurrent { get; set; } = 1; + public uint LevelCurrent { get; set; } = 1; /// /// 最大等级 @@ -43,7 +45,7 @@ internal class Calculable /// 目标等级 /// [JsonIgnore] - public int LevelTarget { get; set; } + public uint LevelTarget { get; set; } /// /// 转化到提升差异 diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Event/Calculate/GroupCalculable.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Event/Calculate/GroupCalculable.cs index 1e623122..a47ff43c 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Event/Calculate/GroupCalculable.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Event/Calculate/GroupCalculable.cs @@ -13,7 +13,7 @@ internal abstract class GroupCalculable : Calculable /// 组Id /// [JsonPropertyName("group_id")] - public int GroupId { get; set; } + public uint GroupId { get; set; } /// public override PromotionDelta ToPromotionDelta() diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Event/Calculate/Item.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Event/Calculate/Item.cs index 93468585..2ef8573d 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Event/Calculate/Item.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Event/Calculate/Item.cs @@ -39,5 +39,5 @@ internal sealed class Item /// 物品星级 仅有家具为有效值 /// [JsonPropertyName("level")] - public ItemQuality Level { get; set; } + public QualityType Level { get; set; } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Event/Calculate/PromotionDelta.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Event/Calculate/PromotionDelta.cs index abb4972f..c32c939d 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Event/Calculate/PromotionDelta.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/Event/Calculate/PromotionDelta.cs @@ -13,17 +13,17 @@ internal sealed class PromotionDelta /// 物品Id /// [JsonPropertyName("id")] - public int Id { get; set; } + public uint Id { get; set; } /// /// 当前等级 /// [JsonPropertyName("level_current")] - public int LevelCurrent { get; set; } + public uint LevelCurrent { get; set; } /// /// 目标等级 /// [JsonPropertyName("level_target")] - public int LevelTarget { get; set; } + public uint LevelTarget { get; set; } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/Avatar/Avatar.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/Avatar/Avatar.cs index 64e50b45..23466e02 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/Avatar/Avatar.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/Avatar/Avatar.cs @@ -40,19 +40,19 @@ internal class Avatar /// 好感度 /// [JsonPropertyName("fetter")] - public int Fetter { get; set; } + public FetterLevel Fetter { get; set; } /// /// 等级 /// [JsonPropertyName("level")] - public int Level { get; set; } + public Level Level { get; set; } /// /// 稀有度 /// [JsonPropertyName("rarity")] - public ItemQuality Rarity { get; set; } + public QualityType Rarity { get; set; } /// /// 激活的命座数 diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/Avatar/Reliquary.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/Avatar/Reliquary.cs index 60df79f6..32a6bb13 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/Avatar/Reliquary.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/Avatar/Reliquary.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using Snap.Hutao.Model.Intrinsic; +using Snap.Hutao.Model.Primitive; namespace Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Avatar; @@ -15,7 +16,7 @@ internal sealed class Reliquary /// Id /// [JsonPropertyName("id")] - public int Id { get; set; } + public ReliquaryId Id { get; set; } /// /// 名称 @@ -39,13 +40,13 @@ internal sealed class Reliquary /// 稀有度 /// [JsonPropertyName("rarity")] - public ItemQuality Rarity { get; set; } + public QualityType Rarity { get; set; } /// /// 等级 /// [JsonPropertyName("level")] - public int Level { get; set; } + public uint Level { get; set; } /// /// 圣遗物套装 diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/Avatar/Weapon.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/Avatar/Weapon.cs index aca7a305..9f7f9991 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/Avatar/Weapon.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/Avatar/Weapon.cs @@ -40,13 +40,13 @@ internal sealed class Weapon /// 稀有度 /// [JsonPropertyName("rarity")] - public ItemQuality Rarity { get; set; } + public QualityType Rarity { get; set; } /// /// 等级 /// [JsonPropertyName("level")] - public int Level { get; set; } + public Level Level { get; set; } /// /// 突破等级 @@ -70,5 +70,5 @@ internal sealed class Weapon /// 精炼等级 /// [JsonPropertyName("affix_level")] - public int AffixLevel { get; set; } + public uint AffixLevel { get; set; } } diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/CardClient.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/CardClient.cs index b863f3ce..eb13bea3 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/CardClient.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/CardClient.cs @@ -5,7 +5,6 @@ using Snap.Hutao.Core.DependencyInjection.Annotation.HttpClient; using Snap.Hutao.Model.Entity; using Snap.Hutao.Web.Hoyolab.Annotation; using Snap.Hutao.Web.Hoyolab.DynamicSecret; -using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Widget; using Snap.Hutao.Web.Response; using System.Net.Http; @@ -78,12 +77,12 @@ internal sealed class CardClient /// 取消令牌 /// 桌面小组件数据 [ApiInformation(Cookie = CookieType.SToken, Salt = SaltType.X6)] - public async Task>> GetWidgetDataAsync(User user, CancellationToken token) + public async Task> GetWidgetDataAsync(User user, CancellationToken token) { - Response>? resp = await httpClient + Response? resp = await httpClient .SetUser(user, CookieType.SToken) .UseDynamicSecret(DynamicSecretVersion.Gen2, SaltType.X6, false) - .TryCatchGetFromJsonAsync>>(ApiEndpoints.CardWidgetData, options, logger, token) + .TryCatchGetFromJsonAsync>(ApiEndpoints.CardWidgetData2, options, logger, token) .ConfigureAwait(false); return Response.Response.DefaultIfNull(resp); diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/DailyNote/DailyNote.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/DailyNote/DailyNote.cs index 95149d9a..a5110318 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/DailyNote/DailyNote.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/DailyNote/DailyNote.cs @@ -7,27 +7,8 @@ namespace Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.DailyNote; /// 实时便笺 /// [HighQuality] -internal sealed class DailyNote +internal sealed class DailyNote : DailyNoteCommon { - /// - /// 当前树脂 - /// - [JsonPropertyName("current_resin")] - public int CurrentResin { get; set; } - - /// - /// 最大树脂 - /// - [JsonPropertyName("max_resin")] - public int MaxResin { get; set; } - - /// - /// 树脂恢复时间 类型的秒数 - /// - [JsonPropertyName("resin_recovery_time")] - [JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)] - public int ResinRecoveryTime { get; set; } - /// /// 格式化的树脂显示 /// @@ -59,18 +40,6 @@ internal sealed class DailyNote } } - /// - /// 委托完成数 - /// - [JsonPropertyName("finished_task_num")] - public int FinishedTaskNum { get; set; } - - /// - /// 委托总数 - /// - [JsonPropertyName("total_task_num")] - public int TotalTaskNum { get; set; } - /// /// 格式化任务 /// @@ -80,12 +49,6 @@ internal sealed class DailyNote get => $"{FinishedTaskNum}/{TotalTaskNum}"; } - /// - /// 4次委托额外奖励是否领取 - /// - [JsonPropertyName("is_extra_task_reward_received")] - public bool IsExtraTaskRewardReceived { get; set; } - /// /// 每日委托奖励字符串 /// @@ -131,41 +94,10 @@ internal sealed class DailyNote get => $"{ResinDiscountUsedNum}/{ResinDiscountNumLimit}"; } - /// - /// 当前派遣数 - /// - [JsonPropertyName("current_expedition_num")] - public int CurrentExpeditionNum { get; set; } - - /// - /// 最大派遣数 - /// - [JsonPropertyName("max_expedition_num")] - public int MaxExpeditionNum { get; set; } - - /// - /// 派遣 - /// - [JsonPropertyName("expeditions")] - public List Expeditions { get; set; } = default!; - - /// - /// 当前洞天宝钱 - /// - [JsonPropertyName("current_home_coin")] - public int CurrentHomeCoin { get; set; } - - /// - /// 最大洞天宝钱 - /// - [JsonPropertyName("max_home_coin")] - public int MaxHomeCoin { get; set; } - /// /// 洞天宝钱恢复时间 类型的秒数 /// [JsonPropertyName("home_coin_recovery_time")] - [JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)] public int HomeCoinRecoveryTime { get; set; } /// diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/DailyNote/DailyNoteCommon.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/DailyNote/DailyNoteCommon.cs new file mode 100644 index 00000000..935a3019 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/DailyNote/DailyNoteCommon.cs @@ -0,0 +1,76 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +namespace Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.DailyNote; + +/// +/// 实时便笺通用 +/// +internal abstract class DailyNoteCommon +{ + /// + /// 当前派遣数 + /// + [JsonPropertyName("current_expedition_num")] + public int CurrentExpeditionNum { get; set; } + + /// + /// 当前洞天宝钱 + /// + [JsonPropertyName("current_home_coin")] + public int CurrentHomeCoin { get; set; } + + /// + /// 当前树脂 + /// + [JsonPropertyName("current_resin")] + public int CurrentResin { get; set; } + + /// + /// 派遣 + /// + [JsonPropertyName("expeditions")] + public List Expeditions { get; set; } = default!; + + /// + /// 委托完成数 + /// + [JsonPropertyName("finished_task_num")] + public int FinishedTaskNum { get; set; } + + /// + /// 4次委托额外奖励是否领取 + /// + [JsonPropertyName("is_extra_task_reward_received")] + public bool IsExtraTaskRewardReceived { get; set; } + + /// + /// 最大派遣数 + /// + [JsonPropertyName("max_expedition_num")] + public int MaxExpeditionNum { get; set; } + + /// + /// 最大洞天宝钱 + /// + [JsonPropertyName("max_home_coin")] + public int MaxHomeCoin { get; set; } + + /// + /// 最大树脂 + /// + [JsonPropertyName("max_resin")] + public int MaxResin { get; set; } + + /// + /// 树脂恢复时间 类型的秒数 + /// + [JsonPropertyName("resin_recovery_time")] + public int ResinRecoveryTime { get; set; } + + /// + /// 委托总数 + /// + [JsonPropertyName("total_task_num")] + public int TotalTaskNum { get; set; } +} diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/DailyNote/Expedition.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/DailyNote/Expedition.cs index 20975bcc..ceef0ebf 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/DailyNote/Expedition.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/DailyNote/Expedition.cs @@ -39,7 +39,6 @@ internal sealed class Expedition /// 剩余时间 /// [JsonPropertyName("remained_time")] - [JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)] public int RemainedTime { get; set; } /// diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/DailyNote/ExpeditionStatus.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/DailyNote/ExpeditionStatus.cs index 9f929e8d..541b7af4 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/DailyNote/ExpeditionStatus.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/DailyNote/ExpeditionStatus.cs @@ -9,13 +9,13 @@ namespace Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.DailyNote; [HighQuality] internal enum ExpeditionStatus { - /// - /// 进行中 - /// - Ongoing, - /// /// 完成 /// Finished, + + /// + /// 进行中 + /// + Ongoing, } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/DailyNote/WidgetDailyNote.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/DailyNote/WidgetDailyNote.cs new file mode 100644 index 00000000..9ff9efa0 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/DailyNote/WidgetDailyNote.cs @@ -0,0 +1,22 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +namespace Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.DailyNote; + +/// +/// 实时便笺小组件数据 +/// +internal sealed class WidgetDailyNote : DailyNoteCommon +{ + /// + /// 是否签到 + /// + [JsonPropertyName("has_signed")] + public bool HasSigned { get; set; } + + /// + /// 签到页面链接 + /// + [JsonPropertyName("sign_url")] + public Uri SignUrl { get; set; } = default!; +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/SpiralAbyss/Avatar.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/SpiralAbyss/Avatar.cs index 3bfae5a6..4961e810 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/SpiralAbyss/Avatar.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/SpiralAbyss/Avatar.cs @@ -1,6 +1,8 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using Snap.Hutao.Model.Primitive; + namespace Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.SpiralAbyss; /// @@ -13,7 +15,7 @@ internal sealed class Avatar /// Id /// [JsonPropertyName("id")] - public int Id { get; set; } + public AvatarId Id { get; set; } /// /// 图标 diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/SpiralAbyss/Battle.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/SpiralAbyss/Battle.cs index 4efef4e9..2c89f184 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/SpiralAbyss/Battle.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/SpiralAbyss/Battle.cs @@ -19,7 +19,6 @@ internal sealed class Battle /// 时间戳 /// [JsonPropertyName("timestamp")] - [JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)] public long Timestamp { get; set; } = default!; /// diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/SpiralAbyss/Floor.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/SpiralAbyss/Floor.cs index cc495f67..4a20f960 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/SpiralAbyss/Floor.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/SpiralAbyss/Floor.cs @@ -31,7 +31,6 @@ internal sealed class Floor /// 结束时间 /// [JsonPropertyName("settle_time")] - [JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)] public long SettleTime { get; set; } = default!; /// diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/SpiralAbyss/Rank.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/SpiralAbyss/Rank.cs index 3cce519c..8964640a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/SpiralAbyss/Rank.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/SpiralAbyss/Rank.cs @@ -1,6 +1,8 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using Snap.Hutao.Model.Primitive; + namespace Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.SpiralAbyss; /// @@ -13,7 +15,7 @@ internal sealed class Rank /// 角色Id /// [JsonPropertyName("avatar_id")] - public int AvatarId { get; set; } + public AvatarId AvatarId { get; set; } /// /// 角色图标 diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/SpiralAbyss/SpiralAbyss.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/SpiralAbyss/SpiralAbyss.cs index a4eead2b..9f1c1cab 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/SpiralAbyss/SpiralAbyss.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/SpiralAbyss/SpiralAbyss.cs @@ -19,14 +19,12 @@ internal sealed class SpiralAbyss /// 开始时间 /// [JsonPropertyName("start_time")] - [JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)] public long StartTime { get; set; } /// /// 结束时间 /// [JsonPropertyName("end_time")] - [JsonNumberHandling(JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)] public long EndTime { get; set; } /// diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/Widget/WidgetData.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/Widget/WidgetData.cs deleted file mode 100644 index 9fe391d2..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/Widget/WidgetData.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) DGP Studio. All rights reserved. -// Licensed under the MIT license. - -namespace Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Widget; - -/// -/// 小组件数据 -/// -[HighQuality] -internal sealed class WidgetData -{ - /// - /// 游戏Id 2 - /// - [JsonPropertyName("game_id")] - public int GameId { get; set; } - - /// - /// 游戏内Uid - /// - [JsonPropertyName("game_role_id")] - public string GameRoleId { get; set; } = default!; - - /// - /// 昵称 - /// - [JsonPropertyName("nickname")] - public string Nickname { get; set; } = default!; - - /// - /// 区服 - /// - [JsonPropertyName("region")] - public string Region { get; set; } = default!; - - /// - /// 冒险等阶 - /// - [JsonPropertyName("level")] - public int Level { get; set; } - - /// - /// 背景图片 - /// - [JsonPropertyName("background_image")] - public string BackgroundImage { get; set; } = default!; - - /// - /// 数据 - /// - [JsonPropertyName("data")] - public List Data { get; set; } = default!; - - /// - /// 区服名称 - /// - [JsonPropertyName("region_name")] - public string RegionName { get; set; } = default!; -} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/Widget/WidgetDataItem.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/Widget/WidgetDataItem.cs deleted file mode 100644 index a7dbd902..00000000 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Takumi/GameRecord/Widget/WidgetDataItem.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) DGP Studio. All rights reserved. -// Licensed under the MIT license. - -namespace Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Widget; - -/// -/// 小组件数据项 -/// -[HighQuality] -internal sealed class WidgetDataItem -{ - /// - /// 项目名称 - /// - [JsonPropertyName("name")] - public string Name { get; set; } = default!; - - /// - /// 类型 均为 "String" - /// - [JsonPropertyName("type")] - public string Type { get; set; } = default!; - - /// - /// 显示值 - /// - [JsonPropertyName("value")] - public string Value { get; set; } = default!; -} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/GachaLog/GachaItem.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/GachaLog/GachaItem.cs index d7c72a00..066894a2 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/GachaLog/GachaItem.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/GachaLog/GachaItem.cs @@ -25,7 +25,7 @@ internal sealed class GachaItem /// /// 物品Id /// - public int ItemId { get; set; } + public uint ItemId { get; set; } /// /// 获取时间 diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/AvatarAppearanceRank.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/AvatarAppearanceRank.cs index fa027196..c2c37248 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/AvatarAppearanceRank.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/AvatarAppearanceRank.cs @@ -1,6 +1,8 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using Snap.Hutao.Model.Primitive; + namespace Snap.Hutao.Web.Hutao.Model; /// @@ -17,5 +19,5 @@ internal sealed class AvatarAppearanceRank /// /// 排行 /// - public List> Ranks { get; set; } = default!; + public List> Ranks { get; set; } = default!; } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/AvatarCollocation.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/AvatarCollocation.cs index 2c3cc637..2cfa44ed 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/AvatarCollocation.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/AvatarCollocation.cs @@ -1,6 +1,8 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using Snap.Hutao.Model.Primitive; + namespace Snap.Hutao.Web.Hutao.Model; /// @@ -12,12 +14,12 @@ internal sealed class AvatarCollocation : AvatarBuild /// /// 其他角色 /// - public List> Avatars { get; set; } = default!; + public List> Avatars { get; set; } = default!; /// /// 武器 /// - public List> Weapons { get; set; } = default!; + public List> Weapons { get; set; } = default!; /// /// 圣遗物 diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/AvatarUsageRank.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/AvatarUsageRank.cs index 26e15d61..a6bd71ed 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/AvatarUsageRank.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/AvatarUsageRank.cs @@ -1,6 +1,8 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using Snap.Hutao.Model.Primitive; + namespace Snap.Hutao.Web.Hutao.Model; /// @@ -17,5 +19,5 @@ internal sealed class AvatarUsageRank /// /// 排行 /// - public List> Ranks { get; set; } = default!; + public List> Ranks { get; set; } = default!; } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/Post/SimpleAvatar.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/Post/SimpleAvatar.cs index bef43bf5..241714cf 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/Post/SimpleAvatar.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/Post/SimpleAvatar.cs @@ -1,6 +1,7 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using Snap.Hutao.Model.Primitive; using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.Avatar; namespace Snap.Hutao.Web.Hutao.Model.Post; @@ -26,12 +27,12 @@ internal sealed class SimpleAvatar /// /// 角色 Id /// - public int AvatarId { get; set; } + public AvatarId AvatarId { get; set; } /// /// 武器 Id /// - public int WeaponId { get; set; } + public WeaponId WeaponId { get; set; } /// /// 圣遗物套装Id diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/Post/SimpleBattle.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/Post/SimpleBattle.cs index cc470cb8..a0263152 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/Post/SimpleBattle.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/Post/SimpleBattle.cs @@ -1,6 +1,7 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using Snap.Hutao.Model.Primitive; using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.SpiralAbyss; namespace Snap.Hutao.Web.Hutao.Model.Post; @@ -29,5 +30,5 @@ internal sealed class SimpleBattle /// /// 角色列表 /// - public IEnumerable Avatars { get; set; } = default!; + public IEnumerable Avatars { get; set; } = default!; } diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/Post/SimpleRank.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/Post/SimpleRank.cs index cf701355..73c80517 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/Post/SimpleRank.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/Post/SimpleRank.cs @@ -1,6 +1,7 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using Snap.Hutao.Model.Primitive; using Snap.Hutao.Web.Hoyolab.Takumi.GameRecord.SpiralAbyss; namespace Snap.Hutao.Web.Hutao.Model.Post; @@ -23,7 +24,7 @@ internal sealed class SimpleRank /// /// 角色Id /// - public int AvatarId { get; set; } + public AvatarId AvatarId { get; set; } /// /// 值 diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/ReliquarySet.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/ReliquarySet.cs index 9ac806df..0bc584b2 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/ReliquarySet.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/ReliquarySet.cs @@ -19,7 +19,7 @@ internal sealed class ReliquarySet { string[]? deconstructed = set.Split('-'); - EquipAffixId = int.Parse(deconstructed[0]); + EquipAffixId = uint.Parse(deconstructed[0]); Count = int.Parse(deconstructed[1]); } @@ -36,6 +36,6 @@ internal sealed class ReliquarySet /// public override string ToString() { - return $"{(int)EquipAffixId}-{Count}"; + return $"{EquipAffixId.Value}-{Count}"; } } diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/WeaponCollocation.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/WeaponCollocation.cs index 093f539c..0d170e95 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/WeaponCollocation.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hutao/Model/WeaponCollocation.cs @@ -1,6 +1,8 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using Snap.Hutao.Model.Primitive; + namespace Snap.Hutao.Web.Hutao.Model; /// @@ -12,5 +14,5 @@ internal sealed class WeaponCollocation : WeaponBuild /// /// 其他角色 /// - public List> Avatars { get; set; } = default!; + public List> Avatars { get; set; } = default!; } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Web/HutaoEndpoints.cs b/src/Snap.Hutao/Snap.Hutao/Web/HutaoEndpoints.cs index 7b76ac61..390d4b54 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/HutaoEndpoints.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/HutaoEndpoints.cs @@ -157,6 +157,28 @@ internal static class HutaoEndpoints { return $"{HutaoMetadataSnapGenshinApi}/{locale}/{fileName}"; } + + /// + /// 胡桃元数据2文件 + /// + /// 语言 + /// 文件名称 + /// 路径 + public static string HutaoMetadata2File(string locale, string fileName) + { + return $"{HutaoMetadata2SnapGenshinApi}/Genshin/{locale}/{fileName}"; + } + + /// + /// Github 元数据文件 + /// + /// 语言 + /// 文件名称 + /// 路径 + public static string RawGithubUserContentMetadataFile(string locale, string fileName) + { + return $"{RawGithubUserContentSnapMetadataApi}/Genshin/{locale}/{fileName}"; + } #endregion #region Static & Zip @@ -200,6 +222,8 @@ internal static class HutaoEndpoints private const string HomaSnapGenshinApi = "https://homa.snapgenshin.com"; private const string HutaoMetadataSnapGenshinApi = "https://hutao-metadata.snapgenshin.com"; + private const string HutaoMetadata2SnapGenshinApi = "https://hutao-metadata2.snapgenshin.com"; + private const string RawGithubUserContentSnapMetadataApi = "https://raw.githubusercontent.com/DGP-Studio/Snap.Metadata/main"; private const string StaticSnapGenshinApi = "https://static.snapgenshin.com"; private const string StaticZipSnapGenshinApi = "https://static-zip.snapgenshin.com"; } \ No newline at end of file