diff --git a/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/Activation.cs b/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/Activation.cs index e7b82275..8259b2fd 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/Activation.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/Activation.cs @@ -12,6 +12,7 @@ using Snap.Hutao.Service.Navigation; using System.Diagnostics; using System.IO; using System.Security.Principal; +using Windows.ApplicationModel; namespace Snap.Hutao.Core.LifeCycle; @@ -53,11 +54,6 @@ internal static class Activation /// 是否提升了权限 public static bool GetElevated() { - if (Debugger.IsAttached) - { - return true; - } - using (WindowsIdentity identity = WindowsIdentity.GetCurrent()) { WindowsPrincipal principal = new(identity); @@ -65,6 +61,19 @@ internal static class Activation } } + /// + /// 以管理员模式重启 + /// + /// 任务 + public static async ValueTask RestartAsElevatedAsync() + { + if (GetElevated()) + { + await FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync(); + Process.GetCurrentProcess().Kill(); + } + } + /// /// 响应激活事件 /// 激活事件一般不会在UI线程上触发 diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Windowing/ExtendedWindow.cs b/src/Snap.Hutao/Snap.Hutao/Core/Windowing/ExtendedWindow.cs index dad27a0f..fa8c5780 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Windowing/ExtendedWindow.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Windowing/ExtendedWindow.cs @@ -192,11 +192,6 @@ internal sealed class ExtendedWindow : IRecipient - diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Binding/BaseValue/BaseValueInfo.cs b/src/Snap.Hutao/Snap.Hutao/Model/Binding/BaseValue/BaseValueInfo.cs new file mode 100644 index 00000000..525af597 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/Binding/BaseValue/BaseValueInfo.cs @@ -0,0 +1,167 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using CommunityToolkit.Mvvm.ComponentModel; +using Snap.Hutao.Model.Intrinsic; +using Snap.Hutao.Model.Metadata; + +namespace Snap.Hutao.Model.Binding.BaseValue; + +/// +/// 基础数值信息 +/// +internal sealed class BaseValueInfo : ObservableObject +{ + private readonly List propValues; + private readonly Dictionary> growCurveMap; + private readonly Dictionary? promoteMap; + + private int currentLevel; + private List> values = default!; + private bool promoted = true; + + /// + /// 构造一个新的基础数值信息 + /// + /// 最大等级 + /// 属性与初始值 + /// 生长曲线 + /// 突破加成 + public BaseValueInfo(int maxLevel, List propValues, Dictionary> growCurveMap, Dictionary? promoteMap = null) + { + this.propValues = propValues; + this.growCurveMap = growCurveMap; + this.promoteMap = promoteMap; + + MaxLevel = maxLevel; + CurrentLevel = maxLevel; + } + + /// + /// 最大等级 + /// + public int MaxLevel { get; } + + /// + /// 对应的基础值 + /// + public List> Values { get => values; set => SetProperty(ref values, value); } + + /// + /// 当前等级 + /// + public int CurrentLevel + { + get => currentLevel; + set + { + if (SetProperty(ref currentLevel, value)) + { + OnPropertyChanged(nameof(CurrentLevelFormatted)); + UpdateValues(value, promoted); + } + } + } + + /// + /// 格式化当前等级 + /// + public string CurrentLevelFormatted + { + get => $"Lv.{CurrentLevel}"; + } + + /// + /// 是否突破 + /// + public bool Promoted + { + get => promoted; + set + { + if (SetProperty(ref promoted, value)) + { + UpdateValues(currentLevel, value); + } + } + } + + private void UpdateValues(int level, bool promoted) + { + List> values = new(propValues.Count); + + foreach (PropertyCurveValue propValue in propValues) + { + 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); + + value += addValue; + } + + values.Add(Metadata.Converter.PropertyDescriptor.FormatNameValue(propValue.Property, value)); + } + + Values = values; + } + + private int GetPromoteLevel(int level, bool promoted) + { + if (MaxLevel <= 70) + { + if (promoted) + { + return level switch + { + >= 60 => 4, + >= 50 => 3, + >= 40 => 2, + >= 20 => 1, + _ => 0, + }; + } + else + { + return level switch + { + > 60 => 4, + > 50 => 3, + > 40 => 2, + > 20 => 1, + _ => 0, + }; + } + } + else + { + if (promoted) + { + return level switch + { + >= 80 => 6, + >= 70 => 5, + >= 60 => 4, + >= 50 => 3, + >= 40 => 2, + >= 20 => 1, + _ => 0, + }; + } + else + { + return level switch + { + > 80 => 6, + > 70 => 5, + > 60 => 4, + > 50 => 3, + > 40 => 2, + > 20 => 1, + _ => 0, + }; + } + } + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Binding/BaseValue/PropertyCurveValue.cs b/src/Snap.Hutao/Snap.Hutao/Model/Binding/BaseValue/PropertyCurveValue.cs new file mode 100644 index 00000000..448f95d1 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/Binding/BaseValue/PropertyCurveValue.cs @@ -0,0 +1,40 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.Model.Intrinsic; + +namespace Snap.Hutao.Model.Binding.BaseValue; + +/// +/// 战斗属性与初始值 +/// +internal sealed class PropertyCurveValue +{ + /// + /// 构造一个新的战斗属性与初始值 + /// + /// 战斗属性 + /// 类型 + /// 初始值 + public PropertyCurveValue(FightProperty property, GrowCurveType type, float value) + { + Property = property; + Type = type; + Value = value; + } + + /// + /// 战斗属性值 + /// + public FightProperty Property { get; } + + /// + /// 曲线类型 + /// + public GrowCurveType Type { get; } + + /// + /// 初始值 + /// + public float Value { get; } +} diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Binding/Item.cs b/src/Snap.Hutao/Snap.Hutao/Model/Binding/Item.cs index e3780a50..2567d08a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Binding/Item.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Binding/Item.cs @@ -30,4 +30,4 @@ internal class Item : INameIcon /// 星级 /// public ItemQuality Quality { get; set; } -} +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Calculable/CalculableAvatar.cs b/src/Snap.Hutao/Snap.Hutao/Model/Calculable/CalculableAvatar.cs index c24cb86c..3388bf55 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Calculable/CalculableAvatar.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Calculable/CalculableAvatar.cs @@ -25,7 +25,7 @@ internal sealed class CalculableAvatar : ObservableObject, ICalculableAvatar { AvatarId = avatar.Id; LevelMin = 1; - LevelMax = int.Parse(avatar.Property.Parameters.Last().Level); + LevelMax = 90; Skills = avatar.SkillDepot.EnumerateCompositeSkillsNoInherents().Select(p => p.ToCalculable()).ToList(); Name = avatar.Name; Icon = AvatarIconConverter.IconNameToUri(avatar.Icon); diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Calculable/CalculableWeapon.cs b/src/Snap.Hutao/Snap.Hutao/Model/Calculable/CalculableWeapon.cs index cb630960..1e8d483c 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Calculable/CalculableWeapon.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Calculable/CalculableWeapon.cs @@ -25,7 +25,7 @@ internal class CalculableWeapon : ObservableObject, ICalculableWeapon { WeaponId = weapon.Id; LevelMin = 1; - LevelMax = int.Parse(weapon.Property.Parameters.Last().Level); + LevelMax = (int)weapon.Quality >= 3 ? 90 : 70; Name = weapon.Name; Icon = EquipIconConverter.IconNameToUri(weapon.Icon); Quality = weapon.RankLevel; diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/GrowCurveType.cs b/src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/GrowCurveType.cs new file mode 100644 index 00000000..44e3ddc5 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/GrowCurveType.cs @@ -0,0 +1,74 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +namespace Snap.Hutao.Model.Intrinsic; + +/// +/// 生长曲线 +/// +[HighQuality] +[SuppressMessage("", "SA1602")] +internal enum GrowCurveType +{ + GROW_CURVE_NONE = 0, + GROW_CURVE_HP = 1, + GROW_CURVE_ATTACK = 2, + GROW_CURVE_STAMINA = 3, + GROW_CURVE_STRIKE = 4, + GROW_CURVE_ANTI_STRIKE = 5, + GROW_CURVE_ANTI_STRIKE1 = 6, + GROW_CURVE_ANTI_STRIKE2 = 7, + GROW_CURVE_ANTI_STRIKE3 = 8, + GROW_CURVE_STRIKE_HURT = 9, + GROW_CURVE_ELEMENT = 10, + GROW_CURVE_KILL_EXP = 11, + GROW_CURVE_DEFENSE = 12, + GROW_CURVE_ATTACK_BOMB = 13, + GROW_CURVE_HP_LITTLEMONSTER = 14, + GROW_CURVE_ELEMENT_MASTERY = 15, + GROW_CURVE_PROGRESSION = 16, + GROW_CURVE_DEFENDING = 17, + GROW_CURVE_MHP = 18, + GROW_CURVE_MATK = 19, + GROW_CURVE_TOWERATK = 20, + GROW_CURVE_HP_S5 = 21, + GROW_CURVE_HP_S4 = 22, + GROW_CURVE_HP_2 = 23, + GROW_CURVE_ATTACK_2 = 24, + 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, + GROW_CURVE_CRITICAL_304 = 2304, + GROW_CURVE_CRITICAL_305 = 2305, +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/MonsterType.cs b/src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/MonsterType.cs new file mode 100644 index 00000000..3502d065 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/MonsterType.cs @@ -0,0 +1,20 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +namespace Snap.Hutao.Model.Intrinsic; + +/// +/// 怪物种类 +/// +[HighQuality] +[SuppressMessage("", "SA1602")] +internal enum MonsterType +{ + MONSTER_NONE = 0, + MONSTER_ORDINARY = 1, + MONSTER_BOSS = 2, + MONSTER_ENV_ANIMAL = 3, + MONSTER_LITTLE_MONSTER = 4, + MONSTER_FISH = 5, + MONSTER_PARTNER = 6, +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/WeaponType.cs b/src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/WeaponType.cs index 869a3108..30e58aaf 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/WeaponType.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/WeaponType.cs @@ -95,4 +95,4 @@ internal enum WeaponType /// [LocalizationKey("ModelIntrinsicWeaponTypePole")] WEAPON_POLE = 13, -} +} \ 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 c9f00c62..1de06732 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 @@ -32,6 +32,11 @@ internal partial class Avatar : IStatisticsItemSource, ISummaryItemSource, IName /// public List? CultivationItemsView { get; set; } + /// + /// 最大等级 + /// + public int MaxLevel { get => 90; } + /// 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 4b38d66d..f731742e 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/Avatar.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Avatar/Avatar.cs @@ -18,6 +18,11 @@ internal partial class Avatar /// public AvatarId Id { get; set; } + /// + /// 突破提升 Id 外键 + /// + public PromoteId PromoteId { get; set; } + /// /// 排序号 /// @@ -65,9 +70,15 @@ internal partial class Avatar public WeaponType Weapon { get; set; } /// - /// 属性 + /// 基础数值 /// - public PropertiesParameters Property { get; set; } = default!; + public BaseValue BaseValue { get; set; } = default!; + + /// + /// 生长曲线 + /// + [JsonConverter(typeof(Core.Json.Converter.StringEnumKeyDictionaryConverter))] + public Dictionary GrowCurves { get; set; } = default!; /// /// 技能 diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/AvatarIds.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/AvatarIds.cs index c76b8197..930d2a8b 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/AvatarIds.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/AvatarIds.cs @@ -12,7 +12,6 @@ namespace Snap.Hutao.Model.Metadata; [SuppressMessage("", "SA1600")] internal static class AvatarIds { - public static readonly AvatarId Kate = 10000001; public static readonly AvatarId Ayaka = 10000002; public static readonly AvatarId Qin = 10000003; @@ -107,6 +106,7 @@ internal static class AvatarIds SideIcon = "UI_AvatarIcon_Side_PlayerBoy", Quality = Intrinsic.ItemQuality.QUALITY_ORANGE, }, + [PlayerGirl] = new() { Name = "旅行者", diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/BaseValue.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/BaseValue.cs new file mode 100644 index 00000000..c828de94 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/BaseValue.cs @@ -0,0 +1,25 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +namespace Snap.Hutao.Model.Metadata; + +/// +/// 基础数值 +/// +internal class BaseValue +{ + /// + /// 基础生命值 + /// + public float HpBase { get; set; } + + /// + /// 基础攻击力 + /// + public float AttackBase { get; set; } + + /// + /// 基础防御力 + /// + public float DefenseBase { get; set; } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/PropertyDescriptor.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/PropertyDescriptor.cs index b125e922..fe5d9ba2 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/PropertyDescriptor.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Converter/PropertyDescriptor.cs @@ -15,7 +15,18 @@ namespace Snap.Hutao.Model.Metadata.Converter; internal sealed class PropertyDescriptor : ValueConverter>?> { /// - /// 格式化对 + /// 格式化名称与值 + /// + /// 属性 + /// 值 + /// + public static NameValue FormatNameValue(FightProperty property, float value) + { + return new(property.GetLocalizedDescription(), FormatValue(property, value)); + } + + /// + /// 格式化名称与描述 /// /// 属性 /// 值 diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/GrowCurve.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/GrowCurve.cs new file mode 100644 index 00000000..89b0eb90 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/GrowCurve.cs @@ -0,0 +1,24 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.Model.Intrinsic; + +namespace Snap.Hutao.Model.Metadata; + +/// +/// 生长曲线 +/// +[HighQuality] +internal sealed class GrowCurve +{ + /// + /// 等级 + /// + public int Level { get; set; } + + /// + /// 曲线 值相乘 + /// + [JsonConverter(typeof(Core.Json.Converter.StringEnumKeyDictionaryConverter))] + public Dictionary Curves { get; set; } = default!; +} \ 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 new file mode 100644 index 00000000..65849b3f --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Monster/Monster.cs @@ -0,0 +1,64 @@ +// 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.Monster; + +/// +/// 敌对生物 +/// +internal sealed class Monster +{ + /// + /// Id + /// + public MonsterId Id { get; set; } + + /// + /// 内部代号 + /// + public string MonsterName { get; set; } = default!; + + /// + /// 标题 + /// + public string Title { get; set; } = default!; + + /// + /// 描述 + /// + public string Description { get; set; } = default!; + + /// + /// 图标 + /// + public string Icon { get; set; } = default!; + + /// + /// 怪物种类 + /// + public MonsterType Type { get; set; } + + /// + /// 强化标签 + /// + public List? Affixes { get; set; } = default!; + + /// + /// 掉落物 Id + /// + public IEnumerable? Drops { get; set; } = default!; + + /// + /// 基本属性 + /// + public MonsterBaseValue BaseValue { get; set; } = default!; + + /// + /// 生长曲线 + /// + [JsonConverter(typeof(Core.Json.Converter.StringEnumKeyDictionaryConverter))] + public Dictionary GrowCurves { get; set; } = default!; +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Monster/MonsterBaseValue.cs b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Monster/MonsterBaseValue.cs new file mode 100644 index 00000000..3eebf98b --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Monster/MonsterBaseValue.cs @@ -0,0 +1,50 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +namespace Snap.Hutao.Model.Metadata.Monster; + +/// +/// 怪物基本属性 +/// +internal sealed class MonsterBaseValue : BaseValue +{ + /// + /// 火抗 + /// + public float FireSubHurt { get; set; } + + /// + /// 草抗 + /// + public float GrassSubHurt { get; set; } + + /// + /// 水抗 + /// + public float WaterSubHurt { get; set; } + + /// + /// 雷抗 + /// + public float ElecSubHurt { get; set; } + + /// + /// 风抗 + /// + public float WindSubHurt { get; set; } + + /// + /// 冰抗 + /// + public float IceSubHurt { get; set; } + + /// + /// 岩抗 + /// + public float RockSubHurt { get; set; } + + /// + /// 物抗 + /// + public float PhysicalSubHurt { 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 new file mode 100644 index 00000000..5ff1958f --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Promote.cs @@ -0,0 +1,30 @@ +// 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; + +/// +/// 突破加成 +/// +[HighQuality] +internal sealed class Promote +{ + /// + /// Id + /// + public PromoteId Id { get; set; } + + /// + /// 突破等级 + /// + public int Level { get; set; } + + /// + /// 增加的属性 + /// + [JsonConverter(typeof(Core.Json.Converter.StringEnumKeyDictionaryConverter))] + public Dictionary AddProperties { get; set; } = default!; +} \ 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 new file mode 100644 index 00000000..aba413a2 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Weapon/GrowCurveTypeValue.cs @@ -0,0 +1,23 @@ +// 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 40ca2205..4619bd96 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 @@ -28,6 +28,11 @@ internal sealed partial class Weapon : IStatisticsItemSource, ISummaryItemSource get => RankLevel; } + /// + /// 最大等级 + /// + public int MaxLevel { get => ((int)Quality) >= 3 ? 90 : 70; } + /// 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 e2672e07..9ae28860 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Weapon/Weapon.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/Metadata/Weapon/Weapon.cs @@ -17,6 +17,11 @@ internal sealed partial class Weapon /// public WeaponId Id { get; set; } + /// + /// 突破 Id + /// + public PromoteId PromoteId { get; set; } + /// /// 武器类型 /// @@ -48,9 +53,10 @@ internal sealed partial class Weapon public string AwakenIcon { get; set; } = default!; /// - /// 属性 + /// 生长曲线 /// - public PropertiesParameters Property { get; set; } = default!; + [JsonConverter(typeof(Core.Json.Converter.StringEnumKeyDictionaryConverter))] + public Dictionary GrowCurves { get; set; } = default!; /// /// 被动信息, 无被动的武器为 diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Primitive/MonsterId.cs b/src/Snap.Hutao/Snap.Hutao/Model/Primitive/MonsterId.cs new file mode 100644 index 00000000..27fe1524 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/Primitive/MonsterId.cs @@ -0,0 +1,66 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.Model.Primitive.Converter; + +namespace Snap.Hutao.Model.Primitive; + +/// +/// 8位 怪物Id +/// +[HighQuality] +[JsonConverter(typeof(IdentityConverter))] +internal readonly struct MonsterId : IEquatable +{ + /// + /// 值 + /// + public readonly int Value; + + /// + /// Initializes a new instance of the struct. + /// + /// value + public MonsterId(int value) + { + Value = value; + } + + public static implicit operator int(MonsterId value) + { + return value.Value; + } + + public static implicit operator MonsterId(int value) + { + return new(value); + } + + public static bool operator ==(MonsterId left, MonsterId right) + { + return left.Value == right.Value; + } + + public static bool operator !=(MonsterId left, MonsterId right) + { + return !(left == right); + } + + /// + public bool Equals(MonsterId other) + { + return Value == other.Value; + } + + /// + public override bool Equals(object? obj) + { + return obj is MonsterId other && Equals(other); + } + + /// + public override int GetHashCode() + { + return Value.GetHashCode(); + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/Primitive/PromoteId.cs b/src/Snap.Hutao/Snap.Hutao/Model/Primitive/PromoteId.cs new file mode 100644 index 00000000..4c9d0206 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Model/Primitive/PromoteId.cs @@ -0,0 +1,66 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.Model.Primitive.Converter; + +namespace Snap.Hutao.Model.Primitive; + +/// +/// 1-5位 角色突破提升Id +/// +[HighQuality] +[JsonConverter(typeof(IdentityConverter))] +internal readonly struct PromoteId : IEquatable +{ + /// + /// 值 + /// + public readonly int Value; + + /// + /// Initializes a new instance of the struct. + /// + /// value + public PromoteId(int value) + { + Value = value; + } + + public static implicit operator int(PromoteId value) + { + return value.Value; + } + + public static implicit operator PromoteId(int value) + { + return new(value); + } + + public static bool operator ==(PromoteId left, PromoteId right) + { + return left.Value == right.Value; + } + + public static bool operator !=(PromoteId left, PromoteId right) + { + return !(left == right); + } + + /// + public bool Equals(PromoteId other) + { + return Value == other.Value; + } + + /// + public override bool Equals(object? obj) + { + return obj is PromoteId other && Equals(other); + } + + /// + public override int GetHashCode() + { + return Value.GetHashCode(); + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs index f8f6d4e7..78696444 100644 --- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs +++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.Designer.cs @@ -1428,6 +1428,24 @@ namespace Snap.Hutao.Resource.Localization { } } + /// + /// 查找类似 等级 的本地化字符串。 + /// + internal static string ViewControlBaseValueSliderLevel { + get { + return ResourceManager.GetString("ViewControlBaseValueSliderLevel", resourceCulture); + } + } + + /// + /// 查找类似 突破后 的本地化字符串。 + /// + internal static string ViewControlBaseValueSliderPromoted { + get { + return ResourceManager.GetString("ViewControlBaseValueSliderPromoted", resourceCulture); + } + } + /// /// 查找类似 加载中,请稍候 的本地化字符串。 /// diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx index 16c686f4..f0aa03d6 100644 --- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx +++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx @@ -573,6 +573,12 @@ 我的角色 + + 等级 + + + 突破后 + 加载中,请稍候 diff --git a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/ReliquaryWeightConfiguration.cs b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/ReliquaryWeightConfiguration.cs index 36f834c5..e11053f4 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/ReliquaryWeightConfiguration.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/AvatarInfo/Factory/ReliquaryWeightConfiguration.cs @@ -24,7 +24,6 @@ internal static class ReliquaryWeightConfiguration new AffixWeight(AvatarIds.Qin, 0, 75, 0, 100, 100, 0, 55, 100).Anemo().Phyiscal(), new AffixWeight(AvatarIds.Lisa, 0, 75, 0, 100, 100, 75, 0, 0).Electro(), new AffixWeight(AvatarIds.Barbara, 100, 50, 0, 50, 50, 0, 55, 100).Hydro(80), - new AffixWeight(AvatarIds.Barbara, 50, 75, 0, 100, 100, 0, 55, 100, "暴力奶妈").Hydro(), new AffixWeight(AvatarIds.Kaeya, 0, 75, 0, 100, 100, 0, 30, 0).Cryo().Phyiscal(), new AffixWeight(AvatarIds.Diluc, 0, 75, 0, 100, 100, 75, 0, 0).Pyro(), new AffixWeight(AvatarIds.Razor, 0, 75, 0, 100, 100, 0, 0, 0).Electro().Phyiscal(), @@ -37,16 +36,13 @@ internal static class ReliquaryWeightConfiguration new AffixWeight(AvatarIds.Ningguang, 0, 75, 0, 100, 100, 0, 30, 0).Geo(), new AffixWeight(AvatarIds.Klee, 0, 75, 0, 100, 100, 75, 30, 0).Pyro(), new AffixWeight(AvatarIds.Zhongli, 80, 75, 0, 100, 100, 0, 55, 0).Geo().Phyiscal(50), - new AffixWeight(AvatarIds.Zhongli, 100, 55, 0, 100, 100, 0, 55, 0, "血牛钟离").Geo(75), - new AffixWeight(AvatarIds.Zhongli, 100, 55, 0, 100, 100, 0, 75, 0, "血牛钟离(2命+)").Geo(75), new AffixWeight(AvatarIds.Fischl, 0, 75, 0, 100, 100, 75, 0, 0).Electro().Phyiscal(60), new AffixWeight(AvatarIds.Bennett, 100, 50, 0, 100, 100, 0, 55, 100).Pyro(80), new AffixWeight(AvatarIds.Tartaglia, 0, 75, 0, 100, 100, 75, 30, 0).Hydro(), new AffixWeight(AvatarIds.Noel, 0, 50, 90, 100, 100, 0, 70, 0).Geo(), new AffixWeight(AvatarIds.Qiqi, 0, 75, 0, 100, 100, 0, 55, 100).Cryo().Phyiscal(), new AffixWeight(AvatarIds.Chongyun, 0, 75, 0, 100, 100, 75, 55, 0).Cryo(), - new AffixWeight(AvatarIds.Ganyu, 0, 75, 0, 100, 100, 75, 0, 0, "融化流").Cryo(), - new AffixWeight(AvatarIds.Ganyu, 0, 75, 0, 100, 100, 0, 55, 0, "永冻流").Cryo(), + new AffixWeight(AvatarIds.Ganyu, 0, 75, 0, 100, 100, 75, 0, 0).Cryo(), new AffixWeight(AvatarIds.Albedo, 0, 0, 100, 100, 100, 0, 0, 0).Geo(), new AffixWeight(AvatarIds.Diona, 100, 50, 0, 50, 50, 0, 90, 100).Cryo(), new AffixWeight(AvatarIds.Mona, 0, 75, 0, 100, 100, 75, 75, 0).Hydro(), diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/GachaStatisticsExtension.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/GachaStatisticsExtension.cs index fa981cd1..acac0cf0 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/GachaStatisticsExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/Factory/GachaStatisticsExtension.cs @@ -72,10 +72,10 @@ internal static class GachaStatisticsExtension .ToList(); } + [SuppressMessage("", "IDE0057")] private static Color GetColorByName(string name) { Span codes = MD5.HashData(Encoding.UTF8.GetBytes(name)); - Color color = Color.FromArgb(255, codes.Slice(0, 5).Average(), codes.Slice(5, 5).Average(), codes.Slice(10, 5).Average()); - return color; + return Color.FromArgb(255, codes.Slice(0, 5).Average(), codes.Slice(5, 5).Average(), codes.Slice(10, 5).Average()); } } diff --git a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogService.cs b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogService.cs index a8370432..9fa1b050 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/GachaLog/GachaLogService.cs @@ -198,6 +198,8 @@ internal sealed class GachaLogService : IGachaLogService .OrderBy(i => i.Id) .FirstOrDefault()?.Id ?? long.MaxValue; + logger.LogInformation("Last Id to trim with [{id}]", trimId); + IEnumerable toAdd = list .OrderByDescending(i => i.Id) .Where(i => i.Id < trimId) diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/IMetadataService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/IMetadataService.cs index ef01e713..70e9a4a1 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/IMetadataService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/IMetadataService.cs @@ -5,6 +5,7 @@ using Snap.Hutao.Model.Intrinsic; using Snap.Hutao.Model.Metadata; using Snap.Hutao.Model.Metadata.Achievement; using Snap.Hutao.Model.Metadata.Avatar; +using Snap.Hutao.Model.Metadata.Monster; using Snap.Hutao.Model.Metadata.Reliquary; using Snap.Hutao.Model.Metadata.Weapon; using Snap.Hutao.Model.Primitive; @@ -154,5 +155,47 @@ internal interface IMetadataService : ICastableService /// /// 取消令牌 /// 材料列表 - ValueTask> GetMaterialsAsync(CancellationToken token = default(CancellationToken)); + ValueTask> GetMaterialsAsync(CancellationToken token = default); + + /// + /// 异步获取怪物列表 + /// + /// 取消令牌 + /// 怪物列表 + ValueTask> GetMonstersAsync(CancellationToken token = default); + + /// + /// 异步获取等级角色曲线映射 + /// + /// 取消令牌 + /// 等级角色曲线映射 + ValueTask>> GetLevelToAvatarCurveMapAsync(CancellationToken token = default); + + /// + /// 异步获取等级怪物曲线映射 + /// + /// 取消令牌 + /// 等级怪物曲线映射 + ValueTask>> GetLevelToMonsterCurveMapAsync(CancellationToken token = default); + + /// + /// 异步获取等级武器曲线映射 + /// + /// 取消令牌 + /// 等级武器曲线映射 + ValueTask>> GetLevelToWeaponCurveMapAsync(CancellationToken token = default); + + /// + /// 异步获取角色突破列表 + /// + /// 取消令牌 + /// 角色突破列表 + ValueTask> GetAvatarPromotesAsync(CancellationToken token = default); + + /// + /// 异步获取武器突破列表 + /// + /// 取消令牌 + /// 武器突破列表 + ValueTask> GetWeaponPromotesAsync(CancellationToken token = default(CancellationToken)); } \ No newline at end of file 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 dcfc75a4..4d5b66cb 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.Implementation.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.Implementation.cs @@ -4,6 +4,7 @@ using Snap.Hutao.Model.Metadata; using Snap.Hutao.Model.Metadata.Achievement; using Snap.Hutao.Model.Metadata.Avatar; +using Snap.Hutao.Model.Metadata.Monster; using Snap.Hutao.Model.Metadata.Reliquary; using Snap.Hutao.Model.Metadata.Weapon; @@ -32,6 +33,18 @@ internal sealed partial class MetadataService return FromCacheOrFileAsync>("Avatar", token); } + /// + public ValueTask> GetAvatarPromotesAsync(CancellationToken token = default) + { + return FromCacheOrFileAsync>("AvatarPromote", token); + } + + /// + public ValueTask> GetWeaponPromotesAsync(CancellationToken token = default) + { + return FromCacheOrFileAsync>("WeaponPromote", token); + } + /// public ValueTask> GetGachaEventsAsync(CancellationToken token = default) { @@ -44,6 +57,12 @@ internal sealed partial class MetadataService return FromCacheOrFileAsync>("Material", token); } + /// + public ValueTask> GetMonstersAsync(CancellationToken token = default) + { + return FromCacheOrFileAsync>("Monster", token); + } + /// public ValueTask> GetReliquariesAsync(CancellationToken token = default) { 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 db1a17f6..49543eb6 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.Indexing.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.Indexing.cs @@ -51,6 +51,24 @@ internal sealed partial class MetadataService return FromCacheAsDictionaryAsync("Weapon", w => w.Id, token); } + /// + public ValueTask>> GetLevelToAvatarCurveMapAsync(CancellationToken token = default) + { + return FromCacheAsDictionaryAsync, GrowCurve>("AvatarCurve", a => a.Level, a => a.Curves, token); + } + + /// + public ValueTask>> GetLevelToMonsterCurveMapAsync(CancellationToken token = default) + { + return FromCacheAsDictionaryAsync, GrowCurve>("MonsterCurve", m => m.Level, m => m.Curves, token); + } + + /// + public ValueTask>> GetLevelToWeaponCurveMapAsync(CancellationToken token = default) + { + return FromCacheAsDictionaryAsync, GrowCurve>("WeaponCurve", w => w.Level, w => w.Curves, token); + } + /// public ValueTask> GetNameToAvatarMapAsync(CancellationToken token = default) { diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.cs index 0bea045f..ccb42e69 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataService.cs @@ -7,6 +7,7 @@ using Snap.Hutao.Core.Diagnostics; using Snap.Hutao.Core.ExceptionService; using Snap.Hutao.Core.IO; using Snap.Hutao.Service.Abstraction; +using System.Globalization; using System.IO; using System.Net.Http; using System.Net.Http.Json; @@ -29,6 +30,7 @@ internal sealed partial class MetadataService : IMetadataService, IMetadataServi private readonly JsonSerializerOptions options; private readonly ILogger logger; private readonly IMemoryCache memoryCache; + private readonly string locale; /// /// 用于指示初始化是否完成 @@ -58,7 +60,8 @@ internal sealed partial class MetadataService : IMetadataService, IMetadataServi this.memoryCache = memoryCache; httpClient = httpClientFactory.CreateClient(nameof(MetadataService)); - metadataFolderPath = Path.Combine(Core.CoreEnvironment.DataFolder, "Metadata"); + locale = GetTextMapLocale(); + metadataFolderPath = Path.Combine(Core.CoreEnvironment.DataFolder, "Metadata", locale); Directory.CreateDirectory(metadataFolderPath); } @@ -86,6 +89,41 @@ internal sealed partial class MetadataService : IMetadataService, IMetadataServi logger.LogInformation("Metadata initializaion completed in {time}ms", stopwatch.GetElapsedTime().TotalMilliseconds); } + private static string GetTextMapLocale() + { + CultureInfo cultureInfo = CultureInfo.CurrentCulture; + + while (true) + { + if (cultureInfo == CultureInfo.InvariantCulture) + { + // Fallback to Chinese. + return "CHS"; + } + + switch (cultureInfo.Name) + { + case "de": return "DE"; // German + case "en": return "EN"; // English + case "es": return "ES"; // Spanish + case "fr": return "FR"; // French + case "id": return "ID"; // Indonesian + case "it": return "IT"; // Italian + case "ja": return "JP"; // Japanese + case "kr": return "JP"; // Japanese + case "ko": return "KR"; // Korean + case "pt": return "PT"; // Portuguese + case "ru": return "RU"; // Russian + case "th": return "TH"; // Thai + case "tr": return "TR"; // Turkish + case "vi": return "TR"; // Vietnamese + case "zh-CHS": return "CHS"; // Chinese (Simplified) Legacy + case "zh-CHT": return "CHT"; // Chinese (Traditional) Legacy + default: cultureInfo = cultureInfo.Parent; break; + } + } + } + private async Task TryUpdateMetadataAsync(CancellationToken token) { IDictionary? metaMd5Map; @@ -93,7 +131,7 @@ internal sealed partial class MetadataService : IMetadataService, IMetadataServi { // download meta check file metaMd5Map = await httpClient - .GetFromJsonAsync>(Web.HutaoEndpoints.HutaoMetadataFile(MetaFileName), options, token) + .GetFromJsonAsync>(Web.HutaoEndpoints.HutaoMetadataFile(locale, MetaFileName), options, token) .ConfigureAwait(false); if (metaMd5Map is null) @@ -162,7 +200,7 @@ internal sealed partial class MetadataService : IMetadataService, IMetadataServi private async Task DownloadMetadataAsync(string fileFullName, CancellationToken token) { Stream sourceStream = await httpClient - .GetStreamAsync(Web.HutaoEndpoints.HutaoMetadataFile(fileFullName), token) + .GetStreamAsync(Web.HutaoEndpoints.HutaoMetadataFile(locale, fileFullName), token) .ConfigureAwait(false); // Write stream while convert LF to CRLF diff --git a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj index f7ce0041..e87a360d 100644 --- a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj +++ b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj @@ -71,6 +71,7 @@ + @@ -178,7 +179,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -442,4 +443,9 @@ SH.Designer.cs + + + MSBuild:Compile + + diff --git a/src/Snap.Hutao/Snap.Hutao/View/Control/BaseValueSlider.xaml b/src/Snap.Hutao/Snap.Hutao/View/Control/BaseValueSlider.xaml new file mode 100644 index 00000000..3650ac76 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/View/Control/BaseValueSlider.xaml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Snap.Hutao/Snap.Hutao/View/Control/BaseValueSlider.xaml.cs b/src/Snap.Hutao/Snap.Hutao/View/Control/BaseValueSlider.xaml.cs new file mode 100644 index 00000000..ac4ec11e --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/View/Control/BaseValueSlider.xaml.cs @@ -0,0 +1,34 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Snap.Hutao.Control; +using Snap.Hutao.Model.Binding.BaseValue; + +namespace Snap.Hutao.View.Control; + +/// +/// ֵ +/// +internal sealed partial class BaseValueSlider : UserControl +{ + private static readonly DependencyProperty BaseValueInfoProperty = Property.Depend(nameof(BaseValueInfo)); + + /// + /// һµĻֵ + /// + public BaseValueSlider() + { + InitializeComponent(); + } + + /// + /// ֵϢ + /// + public BaseValueInfo BaseValueInfo + { + get => (BaseValueInfo)GetValue(BaseValueInfoProperty); + set => SetValue(BaseValueInfoProperty, value); + } +} \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/View/Page/WikiAvatarPage.xaml b/src/Snap.Hutao/Snap.Hutao/View/Page/WikiAvatarPage.xaml index 99bfaa20..5ab08886 100644 --- a/src/Snap.Hutao/Snap.Hutao/View/Page/WikiAvatarPage.xaml +++ b/src/Snap.Hutao/Snap.Hutao/View/Page/WikiAvatarPage.xaml @@ -289,13 +289,11 @@ - - + BaseValueInfo="{Binding BaseValueInfo, Mode=OneWay}"/> - + BaseValueInfo="{Binding BaseValueInfo, Mode=OneWay}"/> >? levelAvatarCurveMap; + private List? promotes; /// /// 构造一个新的角色资料视图模型 @@ -66,7 +71,21 @@ internal sealed class WikiAvatarViewModel : Abstraction.ViewModel /// /// 选中的角色 /// - public Avatar? Selected { get => selected; set => SetProperty(ref selected, value); } + public Avatar? Selected + { + get => selected; set + { + if (SetProperty(ref selected, value)) + { + UpdateBaseValueInfo(value); + } + } + } + + /// + /// 基础数值信息 + /// + public BaseValueInfo? BaseValueInfo { get => baseValueInfo; set => SetProperty(ref baseValueInfo, value); } /// /// 筛选文本 @@ -92,6 +111,9 @@ internal sealed class WikiAvatarViewModel : Abstraction.ViewModel { if (await metadataService.InitializeAsync().ConfigureAwait(false)) { + levelAvatarCurveMap = await metadataService.GetLevelToAvatarCurveMapAsync().ConfigureAwait(false); + promotes = await metadataService.GetAvatarPromotesAsync().ConfigureAwait(false); + Dictionary idMaterialMap = await metadataService.GetIdToMaterialMapAsync().ConfigureAwait(false); List avatars = await metadataService.GetAvatarsAsync().ConfigureAwait(false); List sorted = avatars @@ -179,6 +201,30 @@ internal sealed class WikiAvatarViewModel : Abstraction.ViewModel } } + private void UpdateBaseValueInfo(Avatar? avatar) + { + if (avatar == null) + { + BaseValueInfo = null; + } + else + { + Dictionary avatarPromoteMap = promotes!.Where(p => p.Id == avatar.PromoteId).ToDictionary(p => p.Level); + + FightProperty promoteProperty = avatarPromoteMap[0].AddProperties.Keys.Last(); + + 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(promoteProperty, GrowCurveType.GROW_CURVE_NONE, 0), + }; + + BaseValueInfo = new(avatar.MaxLevel, propertyCurveValues, levelAvatarCurveMap!, avatarPromoteMap); + } + } + private void ApplyFilter(string? input) { if (Avatars != null) diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/WikiWeaponViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/WikiWeaponViewModel.cs index bc24caa0..636f7862 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/WikiWeaponViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/WikiWeaponViewModel.cs @@ -5,9 +5,12 @@ using CommunityToolkit.Mvvm.Input; using CommunityToolkit.WinUI.UI; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Primitives; +using Snap.Hutao.Model.Binding.BaseValue; using Snap.Hutao.Model.Binding.Hutao; using Snap.Hutao.Model.Entity.Primitive; +using Snap.Hutao.Model.Intrinsic; using Snap.Hutao.Model.Intrinsic.Immutable; +using Snap.Hutao.Model.Metadata; using Snap.Hutao.Model.Metadata.Weapon; using Snap.Hutao.Model.Primitive; using Snap.Hutao.Service.Abstraction; @@ -44,6 +47,9 @@ internal class WikiWeaponViewModel : Abstraction.ViewModel private AdvancedCollectionView? weapons; private Weapon? selected; private string? filterText; + private BaseValueInfo? baseValueInfo; + private Dictionary>? levelWeaponCurveMap; + private List? promotes; /// /// 构造一个新的武器资料视图模型 @@ -68,7 +74,21 @@ internal class WikiWeaponViewModel : Abstraction.ViewModel /// /// 选中的角色 /// - public Weapon? Selected { get => selected; set => SetProperty(ref selected, value); } + public Weapon? Selected + { + get => selected; set + { + if (SetProperty(ref selected, value)) + { + UpdateBaseValueInfo(value); + } + } + } + + /// + /// 基础数值信息 + /// + public BaseValueInfo? BaseValueInfo { get => baseValueInfo; set => SetProperty(ref baseValueInfo, value); } /// /// 筛选文本 @@ -94,6 +114,9 @@ internal class WikiWeaponViewModel : Abstraction.ViewModel { if (await metadataService.InitializeAsync().ConfigureAwait(false)) { + levelWeaponCurveMap = await metadataService.GetLevelToWeaponCurveMapAsync().ConfigureAwait(false); + promotes = await metadataService.GetWeaponPromotesAsync().ConfigureAwait(false); + List weapons = await metadataService.GetWeaponsAsync().ConfigureAwait(false); List sorted = weapons .Where(weapon => !skippedWeapons.Contains(weapon.Id)) @@ -175,6 +198,24 @@ internal class WikiWeaponViewModel : Abstraction.ViewModel } } + private void UpdateBaseValueInfo(Weapon? weapon) + { + if (weapon == null) + { + BaseValueInfo = null; + } + else + { + 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)) + .ToList(); + + BaseValueInfo = new(weapon.MaxLevel, propertyCurveValues, levelWeaponCurveMap!, weaponPromoteMap); + } + } + private void ApplyFilter(string? input) { if (Weapons != null) @@ -237,7 +278,7 @@ internal class WikiWeaponViewModel : Abstraction.ViewModel if (intrinsics.FightProperties.Contains(value)) { - matches.Add(weapon.Property.Properties.ElementAtOrDefault(1).GetLocalizedDescriptionOrDefault() == value); + matches.Add(weapon.GrowCurves.ElementAtOrDefault(1).Key.GetLocalizedDescriptionOrDefault() == value); continue; } } diff --git a/src/Snap.Hutao/Snap.Hutao/Web/HutaoEndpoints.cs b/src/Snap.Hutao/Snap.Hutao/Web/HutaoEndpoints.cs index d60e16d5..0ecce16a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/HutaoEndpoints.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/HutaoEndpoints.cs @@ -89,11 +89,12 @@ internal static class HutaoEndpoints /// /// 胡桃元数据文件 /// + /// 语言 /// 文件名称 /// 路径 - public static string HutaoMetadataFile(string fileName) + public static string HutaoMetadataFile(string locale, string fileName) { - return $"{HutaoMetadataSnapGenshinApi}/{fileName}"; + return $"{HutaoMetadataSnapGenshinApi}/{locale}/{fileName}"; } #endregion @@ -144,7 +145,12 @@ internal static class HutaoEndpoints } #endregion +#if DEBUG + private const string HutaoMetadataSnapGenshinApi = "http://hutao-metadata-pages.snapgenshin.cn"; +#else private const string HutaoMetadataSnapGenshinApi = "http://hutao-metadata.snapgenshin.com"; +#endif + private const string HomaSnapGenshinApi = "https://homa.snapgenshin.com"; private const string PatcherDGPStudioApi = "https://patcher.dgp-studio.cn"; private const string StaticSnapGenshinApi = "https://static.snapgenshin.com"; diff --git a/src/Snap.Hutao/Snap.Hutao/Win32/MemoryExtension.cs b/src/Snap.Hutao/Snap.Hutao/Win32/MemoryExtension.cs index 72be8bc9..c3fe4d97 100644 --- a/src/Snap.Hutao/Snap.Hutao/Win32/MemoryExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Win32/MemoryExtension.cs @@ -17,7 +17,7 @@ internal static class MemoryExtension /// /// 目标字符数组 /// 结果字符串 - public static unsafe string AsString(this ref __CHAR_256 char256) + public static unsafe string AsString(this in __CHAR_256 char256) { fixed (CHAR* pszModule = &char256._0) { diff --git a/src/Snap.Hutao/Snap.Hutao/app.manifest b/src/Snap.Hutao/Snap.Hutao/app.manifest index 2c8bda9f..93aa8683 100644 --- a/src/Snap.Hutao/Snap.Hutao/app.manifest +++ b/src/Snap.Hutao/Snap.Hutao/app.manifest @@ -4,12 +4,7 @@ - - true/PM - PerMonitorV2, PerMonitor + PerMonitorV2