mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
avatar & weapon level slider
This commit is contained in:
@@ -12,6 +12,7 @@ using Snap.Hutao.Service.Navigation;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Security.Principal;
|
using System.Security.Principal;
|
||||||
|
using Windows.ApplicationModel;
|
||||||
|
|
||||||
namespace Snap.Hutao.Core.LifeCycle;
|
namespace Snap.Hutao.Core.LifeCycle;
|
||||||
|
|
||||||
@@ -53,11 +54,6 @@ internal static class Activation
|
|||||||
/// <returns>是否提升了权限</returns>
|
/// <returns>是否提升了权限</returns>
|
||||||
public static bool GetElevated()
|
public static bool GetElevated()
|
||||||
{
|
{
|
||||||
if (Debugger.IsAttached)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
using (WindowsIdentity identity = WindowsIdentity.GetCurrent())
|
using (WindowsIdentity identity = WindowsIdentity.GetCurrent())
|
||||||
{
|
{
|
||||||
WindowsPrincipal principal = new(identity);
|
WindowsPrincipal principal = new(identity);
|
||||||
@@ -65,6 +61,19 @@ internal static class Activation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 以管理员模式重启
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>任务</returns>
|
||||||
|
public static async ValueTask RestartAsElevatedAsync()
|
||||||
|
{
|
||||||
|
if (GetElevated())
|
||||||
|
{
|
||||||
|
await FullTrustProcessLauncher.LaunchFullTrustProcessForCurrentAppAsync();
|
||||||
|
Process.GetCurrentProcess().Kill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 响应激活事件
|
/// 响应激活事件
|
||||||
/// 激活事件一般不会在UI线程上触发
|
/// 激活事件一般不会在UI线程上触发
|
||||||
|
|||||||
@@ -192,11 +192,6 @@ internal sealed class ExtendedWindow<TWindow> : IRecipient<BackdropTypeChangedMe
|
|||||||
// 48 is the navigation button leftInset
|
// 48 is the navigation button leftInset
|
||||||
RectInt32 dragRect = StructMarshal.RectInt32(new(48, 0), titleBar.ActualSize).Scale(scale);
|
RectInt32 dragRect = StructMarshal.RectInt32(new(48, 0), titleBar.ActualSize).Scale(scale);
|
||||||
appTitleBar.SetDragRectangles(dragRect.Enumerate().ToArray());
|
appTitleBar.SetDragRectangles(dragRect.Enumerate().ToArray());
|
||||||
|
|
||||||
// workaround for https://github.com/microsoft/WindowsAppSDK/issues/2976
|
|
||||||
SizeInt32 size = appWindow.ClientSize;
|
|
||||||
size.Height -= (int)(31 * scale);
|
|
||||||
appWindow.ResizeClient(size);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -18,7 +18,6 @@
|
|||||||
<cwuc:SwitchPresenter.ContentTransitions>
|
<cwuc:SwitchPresenter.ContentTransitions>
|
||||||
<TransitionCollection>
|
<TransitionCollection>
|
||||||
<EntranceThemeTransition/>
|
<EntranceThemeTransition/>
|
||||||
<ContentThemeTransition/>
|
|
||||||
</TransitionCollection>
|
</TransitionCollection>
|
||||||
</cwuc:SwitchPresenter.ContentTransitions>
|
</cwuc:SwitchPresenter.ContentTransitions>
|
||||||
<cwuc:Case>
|
<cwuc:Case>
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 基础数值信息
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class BaseValueInfo : ObservableObject
|
||||||
|
{
|
||||||
|
private readonly List<PropertyCurveValue> propValues;
|
||||||
|
private readonly Dictionary<int, Dictionary<GrowCurveType, float>> growCurveMap;
|
||||||
|
private readonly Dictionary<int, Promote>? promoteMap;
|
||||||
|
|
||||||
|
private int currentLevel;
|
||||||
|
private List<NameValue<string>> values = default!;
|
||||||
|
private bool promoted = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构造一个新的基础数值信息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="maxLevel">最大等级</param>
|
||||||
|
/// <param name="propValues">属性与初始值</param>
|
||||||
|
/// <param name="growCurveMap">生长曲线</param>
|
||||||
|
/// <param name="promoteMap">突破加成</param>
|
||||||
|
public BaseValueInfo(int maxLevel, List<PropertyCurveValue> propValues, Dictionary<int, Dictionary<GrowCurveType, float>> growCurveMap, Dictionary<int, Promote>? promoteMap = null)
|
||||||
|
{
|
||||||
|
this.propValues = propValues;
|
||||||
|
this.growCurveMap = growCurveMap;
|
||||||
|
this.promoteMap = promoteMap;
|
||||||
|
|
||||||
|
MaxLevel = maxLevel;
|
||||||
|
CurrentLevel = maxLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 最大等级
|
||||||
|
/// </summary>
|
||||||
|
public int MaxLevel { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 对应的基础值
|
||||||
|
/// </summary>
|
||||||
|
public List<NameValue<string>> Values { get => values; set => SetProperty(ref values, value); }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当前等级
|
||||||
|
/// </summary>
|
||||||
|
public int CurrentLevel
|
||||||
|
{
|
||||||
|
get => currentLevel;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (SetProperty(ref currentLevel, value))
|
||||||
|
{
|
||||||
|
OnPropertyChanged(nameof(CurrentLevelFormatted));
|
||||||
|
UpdateValues(value, promoted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 格式化当前等级
|
||||||
|
/// </summary>
|
||||||
|
public string CurrentLevelFormatted
|
||||||
|
{
|
||||||
|
get => $"Lv.{CurrentLevel}";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否突破
|
||||||
|
/// </summary>
|
||||||
|
public bool Promoted
|
||||||
|
{
|
||||||
|
get => promoted;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (SetProperty(ref promoted, value))
|
||||||
|
{
|
||||||
|
UpdateValues(currentLevel, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateValues(int level, bool promoted)
|
||||||
|
{
|
||||||
|
List<NameValue<string>> 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,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 战斗属性与初始值
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class PropertyCurveValue
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 构造一个新的战斗属性与初始值
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="property">战斗属性</param>
|
||||||
|
/// <param name="type">类型</param>
|
||||||
|
/// <param name="value">初始值</param>
|
||||||
|
public PropertyCurveValue(FightProperty property, GrowCurveType type, float value)
|
||||||
|
{
|
||||||
|
Property = property;
|
||||||
|
Type = type;
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 战斗属性值
|
||||||
|
/// </summary>
|
||||||
|
public FightProperty Property { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 曲线类型
|
||||||
|
/// </summary>
|
||||||
|
public GrowCurveType Type { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 初始值
|
||||||
|
/// </summary>
|
||||||
|
public float Value { get; }
|
||||||
|
}
|
||||||
@@ -25,7 +25,7 @@ internal sealed class CalculableAvatar : ObservableObject, ICalculableAvatar
|
|||||||
{
|
{
|
||||||
AvatarId = avatar.Id;
|
AvatarId = avatar.Id;
|
||||||
LevelMin = 1;
|
LevelMin = 1;
|
||||||
LevelMax = int.Parse(avatar.Property.Parameters.Last().Level);
|
LevelMax = 90;
|
||||||
Skills = avatar.SkillDepot.EnumerateCompositeSkillsNoInherents().Select(p => p.ToCalculable()).ToList();
|
Skills = avatar.SkillDepot.EnumerateCompositeSkillsNoInherents().Select(p => p.ToCalculable()).ToList();
|
||||||
Name = avatar.Name;
|
Name = avatar.Name;
|
||||||
Icon = AvatarIconConverter.IconNameToUri(avatar.Icon);
|
Icon = AvatarIconConverter.IconNameToUri(avatar.Icon);
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ internal class CalculableWeapon : ObservableObject, ICalculableWeapon
|
|||||||
{
|
{
|
||||||
WeaponId = weapon.Id;
|
WeaponId = weapon.Id;
|
||||||
LevelMin = 1;
|
LevelMin = 1;
|
||||||
LevelMax = int.Parse(weapon.Property.Parameters.Last().Level);
|
LevelMax = (int)weapon.Quality >= 3 ? 90 : 70;
|
||||||
Name = weapon.Name;
|
Name = weapon.Name;
|
||||||
Icon = EquipIconConverter.IconNameToUri(weapon.Icon);
|
Icon = EquipIconConverter.IconNameToUri(weapon.Icon);
|
||||||
Quality = weapon.RankLevel;
|
Quality = weapon.RankLevel;
|
||||||
|
|||||||
74
src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/GrowCurveType.cs
Normal file
74
src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/GrowCurveType.cs
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Model.Intrinsic;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 生长曲线
|
||||||
|
/// </summary>
|
||||||
|
[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,
|
||||||
|
}
|
||||||
20
src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/MonsterType.cs
Normal file
20
src/Snap.Hutao/Snap.Hutao/Model/Intrinsic/MonsterType.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Model.Intrinsic;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 怪物种类
|
||||||
|
/// </summary>
|
||||||
|
[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,
|
||||||
|
}
|
||||||
@@ -32,6 +32,11 @@ internal partial class Avatar : IStatisticsItemSource, ISummaryItemSource, IName
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public List<Material>? CultivationItemsView { get; set; }
|
public List<Material>? CultivationItemsView { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 最大等级
|
||||||
|
/// </summary>
|
||||||
|
public int MaxLevel { get => 90; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ICalculableAvatar ToCalculable()
|
public ICalculableAvatar ToCalculable()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -18,6 +18,11 @@ internal partial class Avatar
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public AvatarId Id { get; set; }
|
public AvatarId Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 突破提升 Id 外键
|
||||||
|
/// </summary>
|
||||||
|
public PromoteId PromoteId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 排序号
|
/// 排序号
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -65,9 +70,15 @@ internal partial class Avatar
|
|||||||
public WeaponType Weapon { get; set; }
|
public WeaponType Weapon { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 属性
|
/// 基础数值
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public PropertiesParameters Property { get; set; } = default!;
|
public BaseValue BaseValue { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 生长曲线
|
||||||
|
/// </summary>
|
||||||
|
[JsonConverter(typeof(Core.Json.Converter.StringEnumKeyDictionaryConverter))]
|
||||||
|
public Dictionary<FightProperty, GrowCurveType> GrowCurves { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 技能
|
/// 技能
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ namespace Snap.Hutao.Model.Metadata;
|
|||||||
[SuppressMessage("", "SA1600")]
|
[SuppressMessage("", "SA1600")]
|
||||||
internal static class AvatarIds
|
internal static class AvatarIds
|
||||||
{
|
{
|
||||||
public static readonly AvatarId Kate = 10000001;
|
|
||||||
public static readonly AvatarId Ayaka = 10000002;
|
public static readonly AvatarId Ayaka = 10000002;
|
||||||
public static readonly AvatarId Qin = 10000003;
|
public static readonly AvatarId Qin = 10000003;
|
||||||
|
|
||||||
@@ -107,6 +106,7 @@ internal static class AvatarIds
|
|||||||
SideIcon = "UI_AvatarIcon_Side_PlayerBoy",
|
SideIcon = "UI_AvatarIcon_Side_PlayerBoy",
|
||||||
Quality = Intrinsic.ItemQuality.QUALITY_ORANGE,
|
Quality = Intrinsic.ItemQuality.QUALITY_ORANGE,
|
||||||
},
|
},
|
||||||
|
|
||||||
[PlayerGirl] = new()
|
[PlayerGirl] = new()
|
||||||
{
|
{
|
||||||
Name = "旅行者",
|
Name = "旅行者",
|
||||||
|
|||||||
25
src/Snap.Hutao/Snap.Hutao/Model/Metadata/BaseValue.cs
Normal file
25
src/Snap.Hutao/Snap.Hutao/Model/Metadata/BaseValue.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Model.Metadata;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 基础数值
|
||||||
|
/// </summary>
|
||||||
|
internal class BaseValue
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 基础生命值
|
||||||
|
/// </summary>
|
||||||
|
public float HpBase { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 基础攻击力
|
||||||
|
/// </summary>
|
||||||
|
public float AttackBase { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 基础防御力
|
||||||
|
/// </summary>
|
||||||
|
public float DefenseBase { get; set; }
|
||||||
|
}
|
||||||
@@ -15,7 +15,18 @@ namespace Snap.Hutao.Model.Metadata.Converter;
|
|||||||
internal sealed class PropertyDescriptor : ValueConverter<PropertiesParameters, List<LevelParameters<string, ParameterDescription>>?>
|
internal sealed class PropertyDescriptor : ValueConverter<PropertiesParameters, List<LevelParameters<string, ParameterDescription>>?>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 格式化对
|
/// 格式化名称与值
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="property">属性</param>
|
||||||
|
/// <param name="value">值</param>
|
||||||
|
/// <returns>对</returns>
|
||||||
|
public static NameValue<string> FormatNameValue(FightProperty property, float value)
|
||||||
|
{
|
||||||
|
return new(property.GetLocalizedDescription(), FormatValue(property, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 格式化名称与描述
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="property">属性</param>
|
/// <param name="property">属性</param>
|
||||||
/// <param name="value">值</param>
|
/// <param name="value">值</param>
|
||||||
|
|||||||
24
src/Snap.Hutao/Snap.Hutao/Model/Metadata/GrowCurve.cs
Normal file
24
src/Snap.Hutao/Snap.Hutao/Model/Metadata/GrowCurve.cs
Normal file
@@ -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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 生长曲线
|
||||||
|
/// </summary>
|
||||||
|
[HighQuality]
|
||||||
|
internal sealed class GrowCurve
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 等级
|
||||||
|
/// </summary>
|
||||||
|
public int Level { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 曲线 值相乘
|
||||||
|
/// </summary>
|
||||||
|
[JsonConverter(typeof(Core.Json.Converter.StringEnumKeyDictionaryConverter))]
|
||||||
|
public Dictionary<GrowCurveType, float> Curves { get; set; } = default!;
|
||||||
|
}
|
||||||
64
src/Snap.Hutao/Snap.Hutao/Model/Metadata/Monster/Monster.cs
Normal file
64
src/Snap.Hutao/Snap.Hutao/Model/Metadata/Monster/Monster.cs
Normal file
@@ -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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 敌对生物
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class Monster
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Id
|
||||||
|
/// </summary>
|
||||||
|
public MonsterId Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 内部代号
|
||||||
|
/// </summary>
|
||||||
|
public string MonsterName { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 标题
|
||||||
|
/// </summary>
|
||||||
|
public string Title { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 描述
|
||||||
|
/// </summary>
|
||||||
|
public string Description { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 图标
|
||||||
|
/// </summary>
|
||||||
|
public string Icon { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 怪物种类
|
||||||
|
/// </summary>
|
||||||
|
public MonsterType Type { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 强化标签
|
||||||
|
/// </summary>
|
||||||
|
public List<string>? Affixes { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 掉落物 Id
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<MaterialId>? Drops { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 基本属性
|
||||||
|
/// </summary>
|
||||||
|
public MonsterBaseValue BaseValue { get; set; } = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 生长曲线
|
||||||
|
/// </summary>
|
||||||
|
[JsonConverter(typeof(Core.Json.Converter.StringEnumKeyDictionaryConverter))]
|
||||||
|
public Dictionary<FightProperty, GrowCurveType> GrowCurves { get; set; } = default!;
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
namespace Snap.Hutao.Model.Metadata.Monster;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 怪物基本属性
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class MonsterBaseValue : BaseValue
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 火抗
|
||||||
|
/// </summary>
|
||||||
|
public float FireSubHurt { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 草抗
|
||||||
|
/// </summary>
|
||||||
|
public float GrassSubHurt { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 水抗
|
||||||
|
/// </summary>
|
||||||
|
public float WaterSubHurt { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 雷抗
|
||||||
|
/// </summary>
|
||||||
|
public float ElecSubHurt { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 风抗
|
||||||
|
/// </summary>
|
||||||
|
public float WindSubHurt { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 冰抗
|
||||||
|
/// </summary>
|
||||||
|
public float IceSubHurt { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 岩抗
|
||||||
|
/// </summary>
|
||||||
|
public float RockSubHurt { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 物抗
|
||||||
|
/// </summary>
|
||||||
|
public float PhysicalSubHurt { get; set; }
|
||||||
|
}
|
||||||
30
src/Snap.Hutao/Snap.Hutao/Model/Metadata/Promote.cs
Normal file
30
src/Snap.Hutao/Snap.Hutao/Model/Metadata/Promote.cs
Normal file
@@ -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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 突破加成
|
||||||
|
/// </summary>
|
||||||
|
[HighQuality]
|
||||||
|
internal sealed class Promote
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Id
|
||||||
|
/// </summary>
|
||||||
|
public PromoteId Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 突破等级
|
||||||
|
/// </summary>
|
||||||
|
public int Level { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 增加的属性
|
||||||
|
/// </summary>
|
||||||
|
[JsonConverter(typeof(Core.Json.Converter.StringEnumKeyDictionaryConverter))]
|
||||||
|
public Dictionary<FightProperty, float> AddProperties { get; set; } = default!;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 生长曲线与值
|
||||||
|
/// </summary>
|
||||||
|
[HighQuality]
|
||||||
|
internal sealed class GrowCurveTypeValue
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 类型
|
||||||
|
/// </summary>
|
||||||
|
public GrowCurveType Type { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 值
|
||||||
|
/// </summary>
|
||||||
|
public float Value { get; set; }
|
||||||
|
}
|
||||||
@@ -28,6 +28,11 @@ internal sealed partial class Weapon : IStatisticsItemSource, ISummaryItemSource
|
|||||||
get => RankLevel;
|
get => RankLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 最大等级
|
||||||
|
/// </summary>
|
||||||
|
public int MaxLevel { get => ((int)Quality) >= 3 ? 90 : 70; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ICalculableWeapon ToCalculable()
|
public ICalculableWeapon ToCalculable()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -17,6 +17,11 @@ internal sealed partial class Weapon
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public WeaponId Id { get; set; }
|
public WeaponId Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 突破 Id
|
||||||
|
/// </summary>
|
||||||
|
public PromoteId PromoteId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 武器类型
|
/// 武器类型
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -48,9 +53,10 @@ internal sealed partial class Weapon
|
|||||||
public string AwakenIcon { get; set; } = default!;
|
public string AwakenIcon { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 属性
|
/// 生长曲线
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public PropertiesParameters Property { get; set; } = default!;
|
[JsonConverter(typeof(Core.Json.Converter.StringEnumKeyDictionaryConverter))]
|
||||||
|
public Dictionary<FightProperty, GrowCurveTypeValue> GrowCurves { get; set; } = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 被动信息, 无被动的武器为 <see langword="null"/>
|
/// 被动信息, 无被动的武器为 <see langword="null"/>
|
||||||
|
|||||||
66
src/Snap.Hutao/Snap.Hutao/Model/Primitive/MonsterId.cs
Normal file
66
src/Snap.Hutao/Snap.Hutao/Model/Primitive/MonsterId.cs
Normal file
@@ -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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 8位 怪物Id
|
||||||
|
/// </summary>
|
||||||
|
[HighQuality]
|
||||||
|
[JsonConverter(typeof(IdentityConverter<MonsterId>))]
|
||||||
|
internal readonly struct MonsterId : IEquatable<MonsterId>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 值
|
||||||
|
/// </summary>
|
||||||
|
public readonly int Value;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="MonsterId"/> struct.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">value</param>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public bool Equals(MonsterId other)
|
||||||
|
{
|
||||||
|
return Value == other.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override bool Equals(object? obj)
|
||||||
|
{
|
||||||
|
return obj is MonsterId other && Equals(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return Value.GetHashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
66
src/Snap.Hutao/Snap.Hutao/Model/Primitive/PromoteId.cs
Normal file
66
src/Snap.Hutao/Snap.Hutao/Model/Primitive/PromoteId.cs
Normal file
@@ -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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 1-5位 角色突破提升Id
|
||||||
|
/// </summary>
|
||||||
|
[HighQuality]
|
||||||
|
[JsonConverter(typeof(IdentityConverter<PromoteId>))]
|
||||||
|
internal readonly struct PromoteId : IEquatable<PromoteId>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 值
|
||||||
|
/// </summary>
|
||||||
|
public readonly int Value;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="PromoteId"/> struct.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">value</param>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public bool Equals(PromoteId other)
|
||||||
|
{
|
||||||
|
return Value == other.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override bool Equals(object? obj)
|
||||||
|
{
|
||||||
|
return obj is PromoteId other && Equals(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return Value.GetHashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1428,6 +1428,24 @@ namespace Snap.Hutao.Resource.Localization {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 等级 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string ViewControlBaseValueSliderLevel {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ViewControlBaseValueSliderLevel", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 突破后 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string ViewControlBaseValueSliderPromoted {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ViewControlBaseValueSliderPromoted", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 加载中,请稍候 的本地化字符串。
|
/// 查找类似 加载中,请稍候 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -573,6 +573,12 @@
|
|||||||
<data name="ViewAvatarPropertyHeader" xml:space="preserve">
|
<data name="ViewAvatarPropertyHeader" xml:space="preserve">
|
||||||
<value>我的角色</value>
|
<value>我的角色</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ViewControlBaseValueSliderLevel" xml:space="preserve">
|
||||||
|
<value>等级</value>
|
||||||
|
</data>
|
||||||
|
<data name="ViewControlBaseValueSliderPromoted" xml:space="preserve">
|
||||||
|
<value>突破后</value>
|
||||||
|
</data>
|
||||||
<data name="ViewControlLoadingText" xml:space="preserve">
|
<data name="ViewControlLoadingText" xml:space="preserve">
|
||||||
<value>加载中,请稍候</value>
|
<value>加载中,请稍候</value>
|
||||||
</data>
|
</data>
|
||||||
|
|||||||
@@ -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.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.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, 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.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.Diluc, 0, 75, 0, 100, 100, 75, 0, 0).Pyro(),
|
||||||
new AffixWeight(AvatarIds.Razor, 0, 75, 0, 100, 100, 0, 0, 0).Electro().Phyiscal(),
|
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.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.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, 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.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.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.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.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.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.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, 75, 0, 0).Cryo(),
|
||||||
new AffixWeight(AvatarIds.Ganyu, 0, 75, 0, 100, 100, 0, 55, 0, "永冻流").Cryo(),
|
|
||||||
new AffixWeight(AvatarIds.Albedo, 0, 0, 100, 100, 100, 0, 0, 0).Geo(),
|
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.Diona, 100, 50, 0, 50, 50, 0, 90, 100).Cryo(),
|
||||||
new AffixWeight(AvatarIds.Mona, 0, 75, 0, 100, 100, 75, 75, 0).Hydro(),
|
new AffixWeight(AvatarIds.Mona, 0, 75, 0, 100, 100, 75, 75, 0).Hydro(),
|
||||||
|
|||||||
@@ -72,10 +72,10 @@ internal static class GachaStatisticsExtension
|
|||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[SuppressMessage("", "IDE0057")]
|
||||||
private static Color GetColorByName(string name)
|
private static Color GetColorByName(string name)
|
||||||
{
|
{
|
||||||
Span<byte> codes = MD5.HashData(Encoding.UTF8.GetBytes(name));
|
Span<byte> 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.FromArgb(255, codes.Slice(0, 5).Average(), codes.Slice(5, 5).Average(), codes.Slice(10, 5).Average());
|
||||||
return color;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -198,6 +198,8 @@ internal sealed class GachaLogService : IGachaLogService
|
|||||||
.OrderBy(i => i.Id)
|
.OrderBy(i => i.Id)
|
||||||
.FirstOrDefault()?.Id ?? long.MaxValue;
|
.FirstOrDefault()?.Id ?? long.MaxValue;
|
||||||
|
|
||||||
|
logger.LogInformation("Last Id to trim with [{id}]", trimId);
|
||||||
|
|
||||||
IEnumerable<GachaItem> toAdd = list
|
IEnumerable<GachaItem> toAdd = list
|
||||||
.OrderByDescending(i => i.Id)
|
.OrderByDescending(i => i.Id)
|
||||||
.Where(i => i.Id < trimId)
|
.Where(i => i.Id < trimId)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using Snap.Hutao.Model.Intrinsic;
|
|||||||
using Snap.Hutao.Model.Metadata;
|
using Snap.Hutao.Model.Metadata;
|
||||||
using Snap.Hutao.Model.Metadata.Achievement;
|
using Snap.Hutao.Model.Metadata.Achievement;
|
||||||
using Snap.Hutao.Model.Metadata.Avatar;
|
using Snap.Hutao.Model.Metadata.Avatar;
|
||||||
|
using Snap.Hutao.Model.Metadata.Monster;
|
||||||
using Snap.Hutao.Model.Metadata.Reliquary;
|
using Snap.Hutao.Model.Metadata.Reliquary;
|
||||||
using Snap.Hutao.Model.Metadata.Weapon;
|
using Snap.Hutao.Model.Metadata.Weapon;
|
||||||
using Snap.Hutao.Model.Primitive;
|
using Snap.Hutao.Model.Primitive;
|
||||||
@@ -154,5 +155,47 @@ internal interface IMetadataService : ICastableService
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="token">取消令牌</param>
|
/// <param name="token">取消令牌</param>
|
||||||
/// <returns>材料列表</returns>
|
/// <returns>材料列表</returns>
|
||||||
ValueTask<List<Material>> GetMaterialsAsync(CancellationToken token = default(CancellationToken));
|
ValueTask<List<Material>> GetMaterialsAsync(CancellationToken token = default);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步获取怪物列表
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="token">取消令牌</param>
|
||||||
|
/// <returns>怪物列表</returns>
|
||||||
|
ValueTask<List<Monster>> GetMonstersAsync(CancellationToken token = default);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步获取等级角色曲线映射
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="token">取消令牌</param>
|
||||||
|
/// <returns>等级角色曲线映射</returns>
|
||||||
|
ValueTask<Dictionary<int, Dictionary<GrowCurveType, float>>> GetLevelToAvatarCurveMapAsync(CancellationToken token = default);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步获取等级怪物曲线映射
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="token">取消令牌</param>
|
||||||
|
/// <returns>等级怪物曲线映射</returns>
|
||||||
|
ValueTask<Dictionary<int, Dictionary<GrowCurveType, float>>> GetLevelToMonsterCurveMapAsync(CancellationToken token = default);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步获取等级武器曲线映射
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="token">取消令牌</param>
|
||||||
|
/// <returns>等级武器曲线映射</returns>
|
||||||
|
ValueTask<Dictionary<int, Dictionary<GrowCurveType, float>>> GetLevelToWeaponCurveMapAsync(CancellationToken token = default);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步获取角色突破列表
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="token">取消令牌</param>
|
||||||
|
/// <returns>角色突破列表</returns>
|
||||||
|
ValueTask<List<Promote>> GetAvatarPromotesAsync(CancellationToken token = default);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步获取武器突破列表
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="token">取消令牌</param>
|
||||||
|
/// <returns>武器突破列表</returns>
|
||||||
|
ValueTask<List<Promote>> GetWeaponPromotesAsync(CancellationToken token = default(CancellationToken));
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
using Snap.Hutao.Model.Metadata;
|
using Snap.Hutao.Model.Metadata;
|
||||||
using Snap.Hutao.Model.Metadata.Achievement;
|
using Snap.Hutao.Model.Metadata.Achievement;
|
||||||
using Snap.Hutao.Model.Metadata.Avatar;
|
using Snap.Hutao.Model.Metadata.Avatar;
|
||||||
|
using Snap.Hutao.Model.Metadata.Monster;
|
||||||
using Snap.Hutao.Model.Metadata.Reliquary;
|
using Snap.Hutao.Model.Metadata.Reliquary;
|
||||||
using Snap.Hutao.Model.Metadata.Weapon;
|
using Snap.Hutao.Model.Metadata.Weapon;
|
||||||
|
|
||||||
@@ -32,6 +33,18 @@ internal sealed partial class MetadataService
|
|||||||
return FromCacheOrFileAsync<List<Avatar>>("Avatar", token);
|
return FromCacheOrFileAsync<List<Avatar>>("Avatar", token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public ValueTask<List<Promote>> GetAvatarPromotesAsync(CancellationToken token = default)
|
||||||
|
{
|
||||||
|
return FromCacheOrFileAsync<List<Promote>>("AvatarPromote", token);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public ValueTask<List<Promote>> GetWeaponPromotesAsync(CancellationToken token = default)
|
||||||
|
{
|
||||||
|
return FromCacheOrFileAsync<List<Promote>>("WeaponPromote", token);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ValueTask<List<GachaEvent>> GetGachaEventsAsync(CancellationToken token = default)
|
public ValueTask<List<GachaEvent>> GetGachaEventsAsync(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
@@ -44,6 +57,12 @@ internal sealed partial class MetadataService
|
|||||||
return FromCacheOrFileAsync<List<Material>>("Material", token);
|
return FromCacheOrFileAsync<List<Material>>("Material", token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public ValueTask<List<Monster>> GetMonstersAsync(CancellationToken token = default)
|
||||||
|
{
|
||||||
|
return FromCacheOrFileAsync<List<Monster>>("Monster", token);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ValueTask<List<Reliquary>> GetReliquariesAsync(CancellationToken token = default)
|
public ValueTask<List<Reliquary>> GetReliquariesAsync(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -51,6 +51,24 @@ internal sealed partial class MetadataService
|
|||||||
return FromCacheAsDictionaryAsync<WeaponId, Weapon>("Weapon", w => w.Id, token);
|
return FromCacheAsDictionaryAsync<WeaponId, Weapon>("Weapon", w => w.Id, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public ValueTask<Dictionary<int, Dictionary<GrowCurveType, float>>> GetLevelToAvatarCurveMapAsync(CancellationToken token = default)
|
||||||
|
{
|
||||||
|
return FromCacheAsDictionaryAsync<int, Dictionary<GrowCurveType, float>, GrowCurve>("AvatarCurve", a => a.Level, a => a.Curves, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public ValueTask<Dictionary<int, Dictionary<GrowCurveType, float>>> GetLevelToMonsterCurveMapAsync(CancellationToken token = default)
|
||||||
|
{
|
||||||
|
return FromCacheAsDictionaryAsync<int, Dictionary<GrowCurveType, float>, GrowCurve>("MonsterCurve", m => m.Level, m => m.Curves, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public ValueTask<Dictionary<int, Dictionary<GrowCurveType, float>>> GetLevelToWeaponCurveMapAsync(CancellationToken token = default)
|
||||||
|
{
|
||||||
|
return FromCacheAsDictionaryAsync<int, Dictionary<GrowCurveType, float>, GrowCurve>("WeaponCurve", w => w.Level, w => w.Curves, token);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public ValueTask<Dictionary<string, Avatar>> GetNameToAvatarMapAsync(CancellationToken token = default)
|
public ValueTask<Dictionary<string, Avatar>> GetNameToAvatarMapAsync(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using Snap.Hutao.Core.Diagnostics;
|
|||||||
using Snap.Hutao.Core.ExceptionService;
|
using Snap.Hutao.Core.ExceptionService;
|
||||||
using Snap.Hutao.Core.IO;
|
using Snap.Hutao.Core.IO;
|
||||||
using Snap.Hutao.Service.Abstraction;
|
using Snap.Hutao.Service.Abstraction;
|
||||||
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.Http.Json;
|
using System.Net.Http.Json;
|
||||||
@@ -29,6 +30,7 @@ internal sealed partial class MetadataService : IMetadataService, IMetadataServi
|
|||||||
private readonly JsonSerializerOptions options;
|
private readonly JsonSerializerOptions options;
|
||||||
private readonly ILogger<MetadataService> logger;
|
private readonly ILogger<MetadataService> logger;
|
||||||
private readonly IMemoryCache memoryCache;
|
private readonly IMemoryCache memoryCache;
|
||||||
|
private readonly string locale;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 用于指示初始化是否完成
|
/// 用于指示初始化是否完成
|
||||||
@@ -58,7 +60,8 @@ internal sealed partial class MetadataService : IMetadataService, IMetadataServi
|
|||||||
this.memoryCache = memoryCache;
|
this.memoryCache = memoryCache;
|
||||||
httpClient = httpClientFactory.CreateClient(nameof(MetadataService));
|
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);
|
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);
|
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<bool> TryUpdateMetadataAsync(CancellationToken token)
|
private async Task<bool> TryUpdateMetadataAsync(CancellationToken token)
|
||||||
{
|
{
|
||||||
IDictionary<string, string>? metaMd5Map;
|
IDictionary<string, string>? metaMd5Map;
|
||||||
@@ -93,7 +131,7 @@ internal sealed partial class MetadataService : IMetadataService, IMetadataServi
|
|||||||
{
|
{
|
||||||
// download meta check file
|
// download meta check file
|
||||||
metaMd5Map = await httpClient
|
metaMd5Map = await httpClient
|
||||||
.GetFromJsonAsync<IDictionary<string, string>>(Web.HutaoEndpoints.HutaoMetadataFile(MetaFileName), options, token)
|
.GetFromJsonAsync<IDictionary<string, string>>(Web.HutaoEndpoints.HutaoMetadataFile(locale, MetaFileName), options, token)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
if (metaMd5Map is null)
|
if (metaMd5Map is null)
|
||||||
@@ -162,7 +200,7 @@ internal sealed partial class MetadataService : IMetadataService, IMetadataServi
|
|||||||
private async Task DownloadMetadataAsync(string fileFullName, CancellationToken token)
|
private async Task DownloadMetadataAsync(string fileFullName, CancellationToken token)
|
||||||
{
|
{
|
||||||
Stream sourceStream = await httpClient
|
Stream sourceStream = await httpClient
|
||||||
.GetStreamAsync(Web.HutaoEndpoints.HutaoMetadataFile(fileFullName), token)
|
.GetStreamAsync(Web.HutaoEndpoints.HutaoMetadataFile(locale, fileFullName), token)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
// Write stream while convert LF to CRLF
|
// Write stream while convert LF to CRLF
|
||||||
|
|||||||
@@ -71,6 +71,7 @@
|
|||||||
<None Remove="Resource\Segoe Fluent Icons.ttf" />
|
<None Remove="Resource\Segoe Fluent Icons.ttf" />
|
||||||
<None Remove="Resource\WelcomeView_Background.png" />
|
<None Remove="Resource\WelcomeView_Background.png" />
|
||||||
<None Remove="stylecop.json" />
|
<None Remove="stylecop.json" />
|
||||||
|
<None Remove="View\Control\BaseValueSlider.xaml" />
|
||||||
<None Remove="View\Control\BottomTextControl.xaml" />
|
<None Remove="View\Control\BottomTextControl.xaml" />
|
||||||
<None Remove="View\Control\DescParamComboBox.xaml" />
|
<None Remove="View\Control\DescParamComboBox.xaml" />
|
||||||
<None Remove="View\Control\ItemIcon.xaml" />
|
<None Remove="View\Control\ItemIcon.xaml" />
|
||||||
@@ -178,7 +179,7 @@
|
|||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.755" />
|
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.755" />
|
||||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.2.230118.102" />
|
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.2.230217.4" />
|
||||||
<PackageReference Include="StyleCop.Analyzers.Unstable" Version="1.2.0.435">
|
<PackageReference Include="StyleCop.Analyzers.Unstable" Version="1.2.0.435">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
@@ -442,4 +443,9 @@
|
|||||||
<LastGenOutput>SH.Designer.cs</LastGenOutput>
|
<LastGenOutput>SH.Designer.cs</LastGenOutput>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Page Update="View\Control\BaseValueSlider.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
57
src/Snap.Hutao/Snap.Hutao/View/Control/BaseValueSlider.xaml
Normal file
57
src/Snap.Hutao/Snap.Hutao/View/Control/BaseValueSlider.xaml
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<UserControl
|
||||||
|
x:Class="Snap.Hutao.View.Control.BaseValueSlider"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
||||||
|
xmlns:wsc="using:WinUICommunity.SettingsUI.Controls"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
|
||||||
|
<StackPanel>
|
||||||
|
<wsc:SettingsGroup Margin="0,-64,0,0" VerticalAlignment="Top">
|
||||||
|
<wsc:Setting Padding="12,0,6,0" Header="{shcm:ResourceString Name=ViewControlBaseValueSliderLevel}">
|
||||||
|
<wsc:Setting.ActionContent>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBlock
|
||||||
|
Margin="8,0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Bind BaseValueInfo.CurrentLevelFormatted, Mode=OneWay}"/>
|
||||||
|
<CheckBox
|
||||||
|
MinWidth="0"
|
||||||
|
Margin="16,0,8,0"
|
||||||
|
Padding="8,0,0,0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
VerticalContentAlignment="Center"
|
||||||
|
Content="{shcm:ResourceString Name=ViewControlBaseValueSliderPromoted}"
|
||||||
|
IsChecked="{x:Bind BaseValueInfo.Promoted, Mode=TwoWay}"/>
|
||||||
|
<Slider
|
||||||
|
MinWidth="240"
|
||||||
|
Margin="16,0,8,0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Maximum="{x:Bind BaseValueInfo.MaxLevel, Mode=OneWay}"
|
||||||
|
Minimum="1"
|
||||||
|
StepFrequency="1"
|
||||||
|
Value="{x:Bind BaseValueInfo.CurrentLevel, Mode=TwoWay}"/>
|
||||||
|
|
||||||
|
</StackPanel>
|
||||||
|
</wsc:Setting.ActionContent>
|
||||||
|
</wsc:Setting>
|
||||||
|
</wsc:SettingsGroup>
|
||||||
|
|
||||||
|
<ItemsControl VerticalAlignment="Top" ItemsSource="{x:Bind BaseValueInfo.Values, Mode=OneWay}">
|
||||||
|
<ItemsControl.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<wsc:Setting
|
||||||
|
Margin="0,2,0,0"
|
||||||
|
Padding="12,0"
|
||||||
|
Header="{Binding Name}">
|
||||||
|
<wsc:Setting.ActionContent>
|
||||||
|
<TextBlock Text="{Binding Value}"/>
|
||||||
|
</wsc:Setting.ActionContent>
|
||||||
|
</wsc:Setting>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
|
</StackPanel>
|
||||||
|
</UserControl>
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
/// </summary>
|
||||||
|
internal sealed partial class BaseValueSlider : UserControl
|
||||||
|
{
|
||||||
|
private static readonly DependencyProperty BaseValueInfoProperty = Property<BaseValueSlider>.Depend<BaseValueInfo>(nameof(BaseValueInfo));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <20><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>µĻ<C2B5><C4BB><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
/// </summary>
|
||||||
|
public BaseValueSlider()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5>Ϣ
|
||||||
|
/// </summary>
|
||||||
|
public BaseValueInfo BaseValueInfo
|
||||||
|
{
|
||||||
|
get => (BaseValueInfo)GetValue(BaseValueInfoProperty);
|
||||||
|
set => SetValue(BaseValueInfoProperty, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -289,13 +289,11 @@
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
<!-- 属性 -->
|
<!-- 属性 -->
|
||||||
<ContentControl
|
<shvc:BaseValueSlider
|
||||||
Margin="16,16,0,0"
|
Margin="16,16,0,0"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
HorizontalContentAlignment="Stretch"
|
HorizontalContentAlignment="Stretch"
|
||||||
Content="{Binding Selected.Property, Mode=OneWay}"
|
BaseValueInfo="{Binding BaseValueInfo, Mode=OneWay}"/>
|
||||||
ContentTemplate="{StaticResource PropertyDataTemplate}"/>
|
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Margin="16,32,0,0"
|
Margin="16,32,0,0"
|
||||||
Style="{StaticResource BaseTextBlockStyle}"
|
Style="{StaticResource BaseTextBlockStyle}"
|
||||||
|
|||||||
@@ -190,12 +190,11 @@
|
|||||||
Margin="16,16,0,0"
|
Margin="16,16,0,0"
|
||||||
Text="{Binding Selected.Description}"
|
Text="{Binding Selected.Description}"
|
||||||
TextWrapping="Wrap"/>
|
TextWrapping="Wrap"/>
|
||||||
<ContentControl
|
<shvc:BaseValueSlider
|
||||||
Margin="16,16,0,0"
|
Margin="16,16,0,0"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
HorizontalContentAlignment="Stretch"
|
HorizontalContentAlignment="Stretch"
|
||||||
Content="{Binding Selected.Property, Mode=OneWay}"
|
BaseValueInfo="{Binding BaseValueInfo, Mode=OneWay}"/>
|
||||||
ContentTemplate="{StaticResource PropertyDataTemplate}"/>
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Margin="16,32,0,0"
|
Margin="16,32,0,0"
|
||||||
Style="{StaticResource BaseTextBlockStyle}"
|
Style="{StaticResource BaseTextBlockStyle}"
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ internal sealed class SettingViewModel : Abstraction.ViewModel
|
|||||||
if (SetProperty(ref selectedCulture, value))
|
if (SetProperty(ref selectedCulture, value))
|
||||||
{
|
{
|
||||||
SettingEntry entry = appDbContext.Settings.SingleOrAdd(SettingEntry.Culture, CultureInfo.CurrentCulture.Name);
|
SettingEntry entry = appDbContext.Settings.SingleOrAdd(SettingEntry.Culture, CultureInfo.CurrentCulture.Name);
|
||||||
entry.Value = selectedCulture.Value;
|
entry.Value = selectedCulture?.Value;
|
||||||
appDbContext.Settings.UpdateAndSave(entry);
|
appDbContext.Settings.UpdateAndSave(entry);
|
||||||
AppInstance.Restart(string.Empty);
|
AppInstance.Restart(string.Empty);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,10 @@ using CommunityToolkit.Mvvm.Input;
|
|||||||
using CommunityToolkit.WinUI.UI;
|
using CommunityToolkit.WinUI.UI;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Primitives;
|
using Microsoft.Extensions.Primitives;
|
||||||
|
using Snap.Hutao.Model.Binding.BaseValue;
|
||||||
using Snap.Hutao.Model.Binding.Hutao;
|
using Snap.Hutao.Model.Binding.Hutao;
|
||||||
using Snap.Hutao.Model.Entity.Primitive;
|
using Snap.Hutao.Model.Entity.Primitive;
|
||||||
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
using Snap.Hutao.Model.Intrinsic.Immutable;
|
using Snap.Hutao.Model.Intrinsic.Immutable;
|
||||||
using Snap.Hutao.Model.Metadata;
|
using Snap.Hutao.Model.Metadata;
|
||||||
using Snap.Hutao.Model.Metadata.Avatar;
|
using Snap.Hutao.Model.Metadata.Avatar;
|
||||||
@@ -42,6 +44,9 @@ internal sealed class WikiAvatarViewModel : Abstraction.ViewModel
|
|||||||
private AdvancedCollectionView? avatars;
|
private AdvancedCollectionView? avatars;
|
||||||
private Avatar? selected;
|
private Avatar? selected;
|
||||||
private string? filterText;
|
private string? filterText;
|
||||||
|
private BaseValueInfo? baseValueInfo;
|
||||||
|
private Dictionary<int, Dictionary<GrowCurveType, float>>? levelAvatarCurveMap;
|
||||||
|
private List<Promote>? promotes;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构造一个新的角色资料视图模型
|
/// 构造一个新的角色资料视图模型
|
||||||
@@ -66,7 +71,21 @@ internal sealed class WikiAvatarViewModel : Abstraction.ViewModel
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 选中的角色
|
/// 选中的角色
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Avatar? Selected { get => selected; set => SetProperty(ref selected, value); }
|
public Avatar? Selected
|
||||||
|
{
|
||||||
|
get => selected; set
|
||||||
|
{
|
||||||
|
if (SetProperty(ref selected, value))
|
||||||
|
{
|
||||||
|
UpdateBaseValueInfo(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 基础数值信息
|
||||||
|
/// </summary>
|
||||||
|
public BaseValueInfo? BaseValueInfo { get => baseValueInfo; set => SetProperty(ref baseValueInfo, value); }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 筛选文本
|
/// 筛选文本
|
||||||
@@ -92,6 +111,9 @@ internal sealed class WikiAvatarViewModel : Abstraction.ViewModel
|
|||||||
{
|
{
|
||||||
if (await metadataService.InitializeAsync().ConfigureAwait(false))
|
if (await metadataService.InitializeAsync().ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
|
levelAvatarCurveMap = await metadataService.GetLevelToAvatarCurveMapAsync().ConfigureAwait(false);
|
||||||
|
promotes = await metadataService.GetAvatarPromotesAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
Dictionary<MaterialId, Material> idMaterialMap = await metadataService.GetIdToMaterialMapAsync().ConfigureAwait(false);
|
Dictionary<MaterialId, Material> idMaterialMap = await metadataService.GetIdToMaterialMapAsync().ConfigureAwait(false);
|
||||||
List<Avatar> avatars = await metadataService.GetAvatarsAsync().ConfigureAwait(false);
|
List<Avatar> avatars = await metadataService.GetAvatarsAsync().ConfigureAwait(false);
|
||||||
List<Avatar> sorted = avatars
|
List<Avatar> sorted = avatars
|
||||||
@@ -179,6 +201,30 @@ internal sealed class WikiAvatarViewModel : Abstraction.ViewModel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void UpdateBaseValueInfo(Avatar? avatar)
|
||||||
|
{
|
||||||
|
if (avatar == null)
|
||||||
|
{
|
||||||
|
BaseValueInfo = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Dictionary<int, Promote> avatarPromoteMap = promotes!.Where(p => p.Id == avatar.PromoteId).ToDictionary(p => p.Level);
|
||||||
|
|
||||||
|
FightProperty promoteProperty = avatarPromoteMap[0].AddProperties.Keys.Last();
|
||||||
|
|
||||||
|
List<PropertyCurveValue> 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)
|
private void ApplyFilter(string? input)
|
||||||
{
|
{
|
||||||
if (Avatars != null)
|
if (Avatars != null)
|
||||||
|
|||||||
@@ -5,9 +5,12 @@ using CommunityToolkit.Mvvm.Input;
|
|||||||
using CommunityToolkit.WinUI.UI;
|
using CommunityToolkit.WinUI.UI;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Primitives;
|
using Microsoft.Extensions.Primitives;
|
||||||
|
using Snap.Hutao.Model.Binding.BaseValue;
|
||||||
using Snap.Hutao.Model.Binding.Hutao;
|
using Snap.Hutao.Model.Binding.Hutao;
|
||||||
using Snap.Hutao.Model.Entity.Primitive;
|
using Snap.Hutao.Model.Entity.Primitive;
|
||||||
|
using Snap.Hutao.Model.Intrinsic;
|
||||||
using Snap.Hutao.Model.Intrinsic.Immutable;
|
using Snap.Hutao.Model.Intrinsic.Immutable;
|
||||||
|
using Snap.Hutao.Model.Metadata;
|
||||||
using Snap.Hutao.Model.Metadata.Weapon;
|
using Snap.Hutao.Model.Metadata.Weapon;
|
||||||
using Snap.Hutao.Model.Primitive;
|
using Snap.Hutao.Model.Primitive;
|
||||||
using Snap.Hutao.Service.Abstraction;
|
using Snap.Hutao.Service.Abstraction;
|
||||||
@@ -44,6 +47,9 @@ internal class WikiWeaponViewModel : Abstraction.ViewModel
|
|||||||
private AdvancedCollectionView? weapons;
|
private AdvancedCollectionView? weapons;
|
||||||
private Weapon? selected;
|
private Weapon? selected;
|
||||||
private string? filterText;
|
private string? filterText;
|
||||||
|
private BaseValueInfo? baseValueInfo;
|
||||||
|
private Dictionary<int, Dictionary<GrowCurveType, float>>? levelWeaponCurveMap;
|
||||||
|
private List<Promote>? promotes;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构造一个新的武器资料视图模型
|
/// 构造一个新的武器资料视图模型
|
||||||
@@ -68,7 +74,21 @@ internal class WikiWeaponViewModel : Abstraction.ViewModel
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 选中的角色
|
/// 选中的角色
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Weapon? Selected { get => selected; set => SetProperty(ref selected, value); }
|
public Weapon? Selected
|
||||||
|
{
|
||||||
|
get => selected; set
|
||||||
|
{
|
||||||
|
if (SetProperty(ref selected, value))
|
||||||
|
{
|
||||||
|
UpdateBaseValueInfo(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 基础数值信息
|
||||||
|
/// </summary>
|
||||||
|
public BaseValueInfo? BaseValueInfo { get => baseValueInfo; set => SetProperty(ref baseValueInfo, value); }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 筛选文本
|
/// 筛选文本
|
||||||
@@ -94,6 +114,9 @@ internal class WikiWeaponViewModel : Abstraction.ViewModel
|
|||||||
{
|
{
|
||||||
if (await metadataService.InitializeAsync().ConfigureAwait(false))
|
if (await metadataService.InitializeAsync().ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
|
levelWeaponCurveMap = await metadataService.GetLevelToWeaponCurveMapAsync().ConfigureAwait(false);
|
||||||
|
promotes = await metadataService.GetWeaponPromotesAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
List<Weapon> weapons = await metadataService.GetWeaponsAsync().ConfigureAwait(false);
|
List<Weapon> weapons = await metadataService.GetWeaponsAsync().ConfigureAwait(false);
|
||||||
List<Weapon> sorted = weapons
|
List<Weapon> sorted = weapons
|
||||||
.Where(weapon => !skippedWeapons.Contains(weapon.Id))
|
.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<int, Promote> weaponPromoteMap = promotes!.Where(p => p.Id == weapon.PromoteId).ToDictionary(p => p.Level);
|
||||||
|
|
||||||
|
List<PropertyCurveValue> 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)
|
private void ApplyFilter(string? input)
|
||||||
{
|
{
|
||||||
if (Weapons != null)
|
if (Weapons != null)
|
||||||
@@ -237,7 +278,7 @@ internal class WikiWeaponViewModel : Abstraction.ViewModel
|
|||||||
|
|
||||||
if (intrinsics.FightProperties.Contains(value))
|
if (intrinsics.FightProperties.Contains(value))
|
||||||
{
|
{
|
||||||
matches.Add(weapon.Property.Properties.ElementAtOrDefault(1).GetLocalizedDescriptionOrDefault() == value);
|
matches.Add(weapon.GrowCurves.ElementAtOrDefault(1).Key.GetLocalizedDescriptionOrDefault() == value);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,11 +89,12 @@ internal static class HutaoEndpoints
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 胡桃元数据文件
|
/// 胡桃元数据文件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="locale">语言</param>
|
||||||
/// <param name="fileName">文件名称</param>
|
/// <param name="fileName">文件名称</param>
|
||||||
/// <returns>路径</returns>
|
/// <returns>路径</returns>
|
||||||
public static string HutaoMetadataFile(string fileName)
|
public static string HutaoMetadataFile(string locale, string fileName)
|
||||||
{
|
{
|
||||||
return $"{HutaoMetadataSnapGenshinApi}/{fileName}";
|
return $"{HutaoMetadataSnapGenshinApi}/{locale}/{fileName}";
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@@ -144,7 +145,12 @@ internal static class HutaoEndpoints
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
private const string HutaoMetadataSnapGenshinApi = "http://hutao-metadata-pages.snapgenshin.cn";
|
||||||
|
#else
|
||||||
private const string HutaoMetadataSnapGenshinApi = "http://hutao-metadata.snapgenshin.com";
|
private const string HutaoMetadataSnapGenshinApi = "http://hutao-metadata.snapgenshin.com";
|
||||||
|
#endif
|
||||||
|
|
||||||
private const string HomaSnapGenshinApi = "https://homa.snapgenshin.com";
|
private const string HomaSnapGenshinApi = "https://homa.snapgenshin.com";
|
||||||
private const string PatcherDGPStudioApi = "https://patcher.dgp-studio.cn";
|
private const string PatcherDGPStudioApi = "https://patcher.dgp-studio.cn";
|
||||||
private const string StaticSnapGenshinApi = "https://static.snapgenshin.com";
|
private const string StaticSnapGenshinApi = "https://static.snapgenshin.com";
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ internal static class MemoryExtension
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="char256">目标字符数组</param>
|
/// <param name="char256">目标字符数组</param>
|
||||||
/// <returns>结果字符串</returns>
|
/// <returns>结果字符串</returns>
|
||||||
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)
|
fixed (CHAR* pszModule = &char256._0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,12 +4,7 @@
|
|||||||
|
|
||||||
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||||
<windowsSettings>
|
<windowsSettings>
|
||||||
<!-- The combination of below two tags have the following effect:
|
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
|
||||||
1) Per-Monitor for >= Windows 10 Anniversary Update
|
|
||||||
2) System < Windows 10 Anniversary Update
|
|
||||||
-->
|
|
||||||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/PM</dpiAware>
|
|
||||||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness>
|
|
||||||
</windowsSettings>
|
</windowsSettings>
|
||||||
</application>
|
</application>
|
||||||
</assembly>
|
</assembly>
|
||||||
|
|||||||
Reference in New Issue
Block a user