monster wiki fullfilled

This commit is contained in:
DismissedLight
2023-02-25 19:12:38 +08:00
parent 54535cd822
commit e50c1b9184
37 changed files with 739 additions and 88 deletions

View File

@@ -79,6 +79,7 @@
<shmmc:GachaAvatarIconConverter x:Key="GachaAvatarIconConverter"/>
<shmmc:GachaEquipIconConverter x:Key="GachaEquipIconConverter"/>
<shmmc:ItemIconConverter x:Key="ItemIconConverter"/>
<shmmc:MonsterIconConverter x:Key="MonsterIconConverter"/>
<shmmc:PropertyDescriptor x:Key="PropertyDescriptor"/>
<shmmc:QualityColorConverter x:Key="QualityColorConverter"/>
<shmmc:WeaponTypeIconConverter x:Key="WeaponTypeIconConverter"/>

View File

@@ -192,7 +192,7 @@ internal sealed class ImageCache : IImageCache, IImageCacheFilePathOperation
else if (message.StatusCode == HttpStatusCode.NotFound)
{
// directly goto https://static.hut.ao
retryCount = 3;
retryCount += 3;
}
else if (message.StatusCode == HttpStatusCode.TooManyRequests)
{

View File

@@ -2,7 +2,7 @@
// Licensed under the MIT license.
using CommunityToolkit.Mvvm.ComponentModel;
using Snap.Hutao.Model.Metadata;
using Snap.Hutao.Model.Metadata.Item;
namespace Snap.Hutao.Model.Binding.Cultivation;

View File

@@ -1,7 +1,7 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Model.Metadata;
using Snap.Hutao.Model.Metadata.Item;
namespace Snap.Hutao.Model.Binding.Cultivation;

View File

@@ -1,8 +1,8 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Model.Metadata;
using Snap.Hutao.Model.Metadata.Avatar;
using Snap.Hutao.Model.Metadata.Item;
using Snap.Hutao.Model.Primitive;
namespace Snap.Hutao.Model.Binding.Hutao;

View File

@@ -2,7 +2,7 @@
// Licensed under the MIT license.
using CommunityToolkit.Mvvm.ComponentModel;
using Snap.Hutao.Model.Metadata;
using Snap.Hutao.Model.Metadata.Item;
namespace Snap.Hutao.Model.Binding.Inventory;

View File

@@ -157,6 +157,8 @@ internal enum FightProperty
/// <summary>
/// 物理抗性提升
/// </summary>
[LocalizationKey("ServiceAvatarInfoPropertyRESPhysical")]
[Format(FormatMethod.Percent)]
FIGHT_PROP_PHYSICAL_SUB_HURT = 29,
/// <summary>
@@ -233,36 +235,50 @@ internal enum FightProperty
/// <summary>
/// 火元素抗性提升
/// </summary>
[LocalizationKey("ServiceAvatarInfoPropertyRESFire")]
[Format(FormatMethod.Percent)]
FIGHT_PROP_FIRE_SUB_HURT = 50,
/// <summary>
/// 雷元素抗性提升
/// </summary>
[LocalizationKey("ServiceAvatarInfoPropertyRESElec")]
[Format(FormatMethod.Percent)]
FIGHT_PROP_ELEC_SUB_HURT = 51,
/// <summary>
/// 雷元素抗性提升
/// </summary>
[LocalizationKey("ServiceAvatarInfoPropertyRESWater")]
[Format(FormatMethod.Percent)]
FIGHT_PROP_WATER_SUB_HURT = 52,
/// <summary>
/// 草元素抗性提升
/// </summary>
[LocalizationKey("ServiceAvatarInfoPropertyRESGrass")]
[Format(FormatMethod.Percent)]
FIGHT_PROP_GRASS_SUB_HURT = 53,
/// <summary>
/// 风元素抗性提升
/// </summary>
[LocalizationKey("ServiceAvatarInfoPropertyRESWind")]
[Format(FormatMethod.Percent)]
FIGHT_PROP_WIND_SUB_HURT = 54,
/// <summary>
/// 岩元素抗性提升
/// </summary>
[LocalizationKey("ServiceAvatarInfoPropertyRESRock")]
[Format(FormatMethod.Percent)]
FIGHT_PROP_ROCK_SUB_HURT = 55,
/// <summary>
/// 冰元素抗性提升
/// </summary>
[LocalizationKey("ServiceAvatarInfoPropertyRESIce")]
[Format(FormatMethod.Percent)]
FIGHT_PROP_ICE_SUB_HURT = 56,
/// <summary>

View File

@@ -1,12 +1,12 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Model.Binding;
using Snap.Hutao.Model.Binding.Gacha;
using Snap.Hutao.Model.Binding.Hutao;
using Snap.Hutao.Model.Calculable;
using Snap.Hutao.Model.Metadata.Abstraction;
using Snap.Hutao.Model.Metadata.Converter;
using Snap.Hutao.Model.Metadata.Item;
namespace Snap.Hutao.Model.Metadata.Avatar;
@@ -47,7 +47,7 @@ internal partial class Avatar : IStatisticsItemSource, ISummaryItemSource, IName
/// 转换为基础物品
/// </summary>
/// <returns>基础物品</returns>
public Item ToItemBase()
public Binding.Item ToItemBase()
{
return new()
{

View File

@@ -1,6 +1,8 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Model.Intrinsic;
namespace Snap.Hutao.Model.Metadata;
/// <summary>
@@ -22,4 +24,20 @@ internal class BaseValue
/// 基础防御力
/// </summary>
public float DefenseBase { get; set; }
/// <summary>
/// 获取值
/// </summary>
/// <param name="fightProperty">战斗属性</param>
/// <returns>值</returns>
public float GetValue(FightProperty fightProperty)
{
return fightProperty switch
{
FightProperty.FIGHT_PROP_BASE_HP => HpBase,
FightProperty.FIGHT_PROP_BASE_ATTACK => AttackBase,
FightProperty.FIGHT_PROP_BASE_DEFENSE => DefenseBase,
_ => 0,
};
}
}

View File

@@ -18,7 +18,14 @@ internal sealed class ItemIconConverter : ValueConverter<string, Uri>
/// <returns>链接</returns>
public static Uri IconNameToUri(string name)
{
return Web.HutaoEndpoints.StaticFile("ItemIcon", $"{name}.png").ToUri();
if (name.StartsWith("UI_RelicIcon_"))
{
return RelicIconConverter.IconNameToUri(name);
}
else
{
return Web.HutaoEndpoints.StaticFile("ItemIcon", $"{name}.png").ToUri();
}
}
/// <inheritdoc/>

View File

@@ -0,0 +1,28 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Control;
namespace Snap.Hutao.Model.Metadata.Converter;
/// <summary>
/// 怪物图标转换器
/// </summary>
internal sealed class MonsterIconConverter : ValueConverter<string, Uri>
{
/// <summary>
/// 名称转Uri
/// </summary>
/// <param name="name">名称</param>
/// <returns>链接</returns>
public static Uri IconNameToUri(string name)
{
return Web.HutaoEndpoints.StaticFile("MonsterIcon", $"{name}.png").ToUri();
}
/// <inheritdoc/>
public override Uri Convert(string from)
{
return IconNameToUri(from);
}
}

View File

@@ -0,0 +1,50 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Model.Intrinsic;
using Snap.Hutao.Model.Primitive;
using System.Collections.Immutable;
namespace Snap.Hutao.Model.Metadata.Item;
/// <summary>
/// 展示物品
/// </summary>
[HighQuality]
internal class Display
{
/// <summary>
/// 物品Id
/// </summary>
public MaterialId Id { get; set; }
/// <summary>
/// 等级
/// </summary>
public ItemQuality RankLevel { get; set; }
/// <summary>
/// 物品类型
/// </summary>
public ItemType ItemType { get; set; }
/// <summary>
/// 图标
/// </summary>
public string Icon { get; set; } = default!;
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; } = default!;
/// <summary>
/// 描述
/// </summary>
public string Description { get; set; } = default!;
/// <summary>
/// 类型描述
/// </summary>
public string TypeDescription { get; set; } = default!;
}

View File

@@ -5,12 +5,12 @@ using Snap.Hutao.Model.Intrinsic;
using Snap.Hutao.Model.Primitive;
using System.Collections.Immutable;
namespace Snap.Hutao.Model.Metadata;
namespace Snap.Hutao.Model.Metadata.Item;
/// <summary>
/// 材料
/// </summary>
internal sealed class Material
internal sealed class Material : Display
{
private static readonly ImmutableHashSet<MaterialId> MondayThursdayItems = new HashSet<MaterialId>
{
@@ -48,46 +48,11 @@ internal sealed class Material
114045, 114046, 114047, 114048, // 谧林涓露
}.ToImmutableHashSet();
/// <summary>
/// 物品Id
/// </summary>
public MaterialId Id { get; set; }
/// <summary>
/// 等级
/// </summary>
public ItemQuality RankLevel { get; set; }
/// <summary>
/// 物品类型
/// </summary>
public ItemType ItemType { get; set; }
/// <summary>
/// 材料类型
/// </summary>
public MaterialType MaterialType { get; set; }
/// <summary>
/// 图标
/// </summary>
public string Icon { get; set; } = default!;
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; } = default!;
/// <summary>
/// 描述
/// </summary>
public string Description { get; set; } = default!;
/// <summary>
/// 类型描述
/// </summary>
public string TypeDescription { get; set; } = default!;
/// <summary>
/// 效果描述
/// </summary>

View File

@@ -2,6 +2,7 @@
// Licensed under the MIT license.
using Snap.Hutao.Model.Intrinsic;
using Snap.Hutao.Model.Metadata.Item;
using Snap.Hutao.Model.Primitive;
namespace Snap.Hutao.Model.Metadata.Monster;
@@ -49,7 +50,7 @@ internal sealed class Monster
/// <summary>
/// 掉落物 Id
/// </summary>
public IEnumerable<MaterialId>? Drops { get; set; } = default!;
public List<MaterialId>? Drops { get; set; } = default!;
/// <summary>
/// 基本属性
@@ -61,4 +62,9 @@ internal sealed class Monster
/// </summary>
[JsonConverter(typeof(Core.Json.Converter.StringEnumKeyDictionaryConverter))]
public Dictionary<FightProperty, GrowCurveType> GrowCurves { get; set; } = default!;
/// <summary>
/// 养成物品视图
/// </summary>
public List<Display>? DropsView { get; set; }
}

View File

@@ -47,4 +47,25 @@ internal sealed class MonsterBaseValue : BaseValue
/// 物抗
/// </summary>
public float PhysicalSubHurt { get; set; }
/// <summary>
/// 抗性
/// </summary>
public List<NameValue<string>> SubHurts
{
get
{
return new()
{
Converter.PropertyDescriptor.FormatNameValue(Intrinsic.FightProperty.FIGHT_PROP_FIRE_SUB_HURT, FireSubHurt),
Converter.PropertyDescriptor.FormatNameValue(Intrinsic.FightProperty.FIGHT_PROP_WATER_SUB_HURT, WaterSubHurt),
Converter.PropertyDescriptor.FormatNameValue(Intrinsic.FightProperty.FIGHT_PROP_GRASS_SUB_HURT, GrassSubHurt),
Converter.PropertyDescriptor.FormatNameValue(Intrinsic.FightProperty.FIGHT_PROP_ELEC_SUB_HURT, ElecSubHurt),
Converter.PropertyDescriptor.FormatNameValue(Intrinsic.FightProperty.FIGHT_PROP_WIND_SUB_HURT, WindSubHurt),
Converter.PropertyDescriptor.FormatNameValue(Intrinsic.FightProperty.FIGHT_PROP_ICE_SUB_HURT, IceSubHurt),
Converter.PropertyDescriptor.FormatNameValue(Intrinsic.FightProperty.FIGHT_PROP_ROCK_SUB_HURT, RockSubHurt),
Converter.PropertyDescriptor.FormatNameValue(Intrinsic.FightProperty.FIGHT_PROP_PHYSICAL_SUB_HURT, PhysicalSubHurt),
};
}
}
}

View File

@@ -63,4 +63,10 @@ internal readonly struct MonsterId : IEquatable<MonsterId>
{
return Value.GetHashCode();
}
/// <inheritdoc/>
public override string ToString()
{
return Value.ToString();
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@@ -924,6 +924,78 @@ namespace Snap.Hutao.Resource.Localization {
}
}
/// <summary>
/// 查找类似 雷元素抗性 的本地化字符串。
/// </summary>
internal static string ServiceAvatarInfoPropertyRESElec {
get {
return ResourceManager.GetString("ServiceAvatarInfoPropertyRESElec", resourceCulture);
}
}
/// <summary>
/// 查找类似 火元素抗性 的本地化字符串。
/// </summary>
internal static string ServiceAvatarInfoPropertyRESFire {
get {
return ResourceManager.GetString("ServiceAvatarInfoPropertyRESFire", resourceCulture);
}
}
/// <summary>
/// 查找类似 草元素抗性 的本地化字符串。
/// </summary>
internal static string ServiceAvatarInfoPropertyRESGrass {
get {
return ResourceManager.GetString("ServiceAvatarInfoPropertyRESGrass", resourceCulture);
}
}
/// <summary>
/// 查找类似 冰元素抗性 的本地化字符串。
/// </summary>
internal static string ServiceAvatarInfoPropertyRESIce {
get {
return ResourceManager.GetString("ServiceAvatarInfoPropertyRESIce", resourceCulture);
}
}
/// <summary>
/// 查找类似 物理抗性 的本地化字符串。
/// </summary>
internal static string ServiceAvatarInfoPropertyRESPhysical {
get {
return ResourceManager.GetString("ServiceAvatarInfoPropertyRESPhysical", resourceCulture);
}
}
/// <summary>
/// 查找类似 岩元素抗性 的本地化字符串。
/// </summary>
internal static string ServiceAvatarInfoPropertyRESRock {
get {
return ResourceManager.GetString("ServiceAvatarInfoPropertyRESRock", resourceCulture);
}
}
/// <summary>
/// 查找类似 水元素抗性 的本地化字符串。
/// </summary>
internal static string ServiceAvatarInfoPropertyRESWater {
get {
return ResourceManager.GetString("ServiceAvatarInfoPropertyRESWater", resourceCulture);
}
}
/// <summary>
/// 查找类似 风元素抗性 的本地化字符串。
/// </summary>
internal static string ServiceAvatarInfoPropertyRESWind {
get {
return ResourceManager.GetString("ServiceAvatarInfoPropertyRESWind", resourceCulture);
}
}
/// <summary>
/// 查找类似 保存养成计划状态失败 的本地化字符串。
/// </summary>
@@ -4218,6 +4290,15 @@ namespace Snap.Hutao.Resource.Localization {
}
}
/// <summary>
/// 查找类似 掉落物品 的本地化字符串。
/// </summary>
internal static string ViewPageWikiMonsterDropItems {
get {
return ResourceManager.GetString("ViewPageWikiMonsterDropItems", resourceCulture);
}
}
/// <summary>
/// 查找类似 战斗数据 的本地化字符串。
/// </summary>
@@ -4533,6 +4614,15 @@ namespace Snap.Hutao.Resource.Localization {
}
}
/// <summary>
/// 查找类似 怪物资料 的本地化字符串。
/// </summary>
internal static string ViewWikiMonsterHeader {
get {
return ResourceManager.GetString("ViewWikiMonsterHeader", resourceCulture);
}
}
/// <summary>
/// 查找类似 武器资料 的本地化字符串。
/// </summary>

View File

@@ -405,6 +405,30 @@
<data name="ServiceAvatarInfoPropertyHp" xml:space="preserve">
<value>生命值</value>
</data>
<data name="ServiceAvatarInfoPropertyRESElec" xml:space="preserve">
<value>雷元素抗性</value>
</data>
<data name="ServiceAvatarInfoPropertyRESFire" xml:space="preserve">
<value>火元素抗性</value>
</data>
<data name="ServiceAvatarInfoPropertyRESGrass" xml:space="preserve">
<value>草元素抗性</value>
</data>
<data name="ServiceAvatarInfoPropertyRESIce" xml:space="preserve">
<value>冰元素抗性</value>
</data>
<data name="ServiceAvatarInfoPropertyRESPhysical" xml:space="preserve">
<value>物理抗性</value>
</data>
<data name="ServiceAvatarInfoPropertyRESRock" xml:space="preserve">
<value>岩元素抗性</value>
</data>
<data name="ServiceAvatarInfoPropertyRESWater" xml:space="preserve">
<value>水元素抗性</value>
</data>
<data name="ServiceAvatarInfoPropertyRESWind" xml:space="preserve">
<value>风元素抗性</value>
</data>
<data name="ServiceCultivationProjectCurrentUserdataCourrpted" xml:space="preserve">
<value>保存养成计划状态失败</value>
</data>
@@ -1503,6 +1527,9 @@
<data name="ViewPageSettingWebview2Header" xml:space="preserve">
<value>Webview2 运行时</value>
</data>
<data name="ViewPageWikiMonsterDropItems" xml:space="preserve">
<value>掉落物品</value>
</data>
<data name="ViewSpiralAbyssBattleHeader" xml:space="preserve">
<value>战斗数据</value>
</data>
@@ -1608,6 +1635,9 @@
<data name="ViewWikiAvatarHeader" xml:space="preserve">
<value>角色资料</value>
</data>
<data name="ViewWikiMonsterHeader" xml:space="preserve">
<value>怪物资料</value>
</data>
<data name="ViewWikiWeaponHeader" xml:space="preserve">
<value>武器资料</value>
</data>

View File

@@ -10,6 +10,7 @@ using Snap.Hutao.Model.Binding;
using Snap.Hutao.Model.Entity;
using Snap.Hutao.Model.Entity.Database;
using Snap.Hutao.Model.Entity.Primitive;
using Snap.Hutao.Model.Metadata.Item;
using Snap.Hutao.Model.Primitive;
using Snap.Hutao.Service.Metadata;
using System.Collections.ObjectModel;
@@ -128,7 +129,7 @@ internal sealed class CultivationService : ICultivationService
}
/// <inheritdoc/>
public List<BindingInventoryItem> GetInventoryItems(CultivateProject cultivateProject, List<Model.Metadata.Material> metadata, ICommand saveCommand)
public List<BindingInventoryItem> GetInventoryItems(CultivateProject cultivateProject, List<Material> metadata, ICommand saveCommand)
{
Guid projectId = cultivateProject.InnerId;
using (IServiceScope scope = scopeFactory.CreateScope())
@@ -139,7 +140,7 @@ internal sealed class CultivationService : ICultivationService
.ToList();
List<BindingInventoryItem> results = new();
foreach (Model.Metadata.Material meta in metadata.Where(m => m.IsInventoryItem()).OrderBy(m => m.Id))
foreach (Material meta in metadata.Where(m => m.IsInventoryItem()).OrderBy(m => m.Id))
{
InventoryItem entity = entities.SingleOrDefault(e => e.ItemId == meta.Id) ?? InventoryItem.Create(projectId, meta.Id);
results.Add(new(entity, meta, saveCommand));
@@ -158,7 +159,7 @@ internal sealed class CultivationService : ICultivationService
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
IMetadataService metadataService = scope.ServiceProvider.GetRequiredService<IMetadataService>();
List<Model.Metadata.Material> materials = await metadataService.GetMaterialsAsync().ConfigureAwait(false);
List<Material> materials = await metadataService.GetMaterialsAsync().ConfigureAwait(false);
Dictionary<AvatarId, Model.Metadata.Avatar.Avatar> idAvatarMap = await metadataService.GetIdToAvatarMapAsync().ConfigureAwait(false);
Dictionary<WeaponId, Model.Metadata.Weapon.Weapon> idWeaponMap = await metadataService.GetIdToWeaponMapAsync().ConfigureAwait(false);
@@ -203,7 +204,7 @@ internal sealed class CultivationService : ICultivationService
List<BindingStatisticsItem> resultItems = new();
AppDbContext appDbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
List<Model.Metadata.Material> materials = await scope.ServiceProvider
List<Material> materials = await scope.ServiceProvider
.GetRequiredService<IMetadataService>()
.GetMaterialsAsync(default)
.ConfigureAwait(false);

View File

@@ -4,7 +4,7 @@
using Snap.Hutao.Model.Binding.Cultivation;
using Snap.Hutao.Model.Entity;
using Snap.Hutao.Model.Entity.Primitive;
using Snap.Hutao.Model.Metadata;
using Snap.Hutao.Model.Metadata.Item;
using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
using System.Collections.ObjectModel;

View File

@@ -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.Item;
using Snap.Hutao.Model.Metadata.Monster;
using Snap.Hutao.Model.Metadata.Reliquary;
using Snap.Hutao.Model.Metadata.Weapon;
@@ -197,5 +198,12 @@ internal interface IMetadataService : ICastableService
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>武器突破列表</returns>
ValueTask<List<Promote>> GetWeaponPromotesAsync(CancellationToken token = default(CancellationToken));
ValueTask<List<Promote>> GetWeaponPromotesAsync(CancellationToken token = default);
/// <summary>
/// 异步获取显示与材料映射
/// </summary>
/// <param name="token">取消令牌</param>
/// <returns>显示与材料映射</returns>
ValueTask<Dictionary<MaterialId, Display>> GetIdToDisplayAndMaterialMapAsync(CancellationToken token = default);
}

View File

@@ -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.Item;
using Snap.Hutao.Model.Metadata.Monster;
using Snap.Hutao.Model.Metadata.Reliquary;
using Snap.Hutao.Model.Metadata.Weapon;

View File

@@ -4,6 +4,7 @@
using Snap.Hutao.Model.Intrinsic;
using Snap.Hutao.Model.Metadata;
using Snap.Hutao.Model.Metadata.Avatar;
using Snap.Hutao.Model.Metadata.Item;
using Snap.Hutao.Model.Metadata.Reliquary;
using Snap.Hutao.Model.Metadata.Weapon;
using Snap.Hutao.Model.Primitive;
@@ -27,6 +28,23 @@ internal sealed partial class MetadataService
return FromCacheAsDictionaryAsync<AvatarId, Avatar>("Avatar", a => a.Id, token);
}
/// <inheritdoc/>
public async ValueTask<Dictionary<MaterialId, Display>> GetIdToDisplayAndMaterialMapAsync(CancellationToken token = default)
{
Dictionary<MaterialId, Display> displays = await FromCacheAsDictionaryAsync<MaterialId, Display>("Display", a => a.Id, token).ConfigureAwait(false);
Dictionary<MaterialId, Material> materials = await FromCacheAsDictionaryAsync<MaterialId, Material>("Material", a => a.Id, token).ConfigureAwait(false);
// TODO: Cache this
Dictionary<MaterialId, Display> results = new(displays);
foreach ((MaterialId id, Display material) in materials)
{
results[id] = material;
}
return results;
}
/// <inheritdoc/>
public ValueTask<Dictionary<MaterialId, Material>> GetIdToMaterialMapAsync(CancellationToken token = default)
{

View File

@@ -65,6 +65,7 @@
<None Remove="Resource\Icon\UI_ItemIcon_210.png" />
<None Remove="Resource\Icon\UI_ItemIcon_210_256.png" />
<None Remove="Resource\Icon\UI_ItemIcon_220021.png" />
<None Remove="Resource\Icon\UI_MarkCustom_TagMonster.png" />
<None Remove="Resource\Icon\UI_MarkQuest_Events_Proce.png" />
<None Remove="Resource\Icon\UI_MarkTower.png" />
<None Remove="Resource\Icon\UI_MarkTower_Tower.png" />
@@ -108,6 +109,7 @@
<None Remove="View\Page\SpiralAbyssRecordPage.xaml" />
<None Remove="View\Page\TestPage.xaml" />
<None Remove="View\Page\WikiAvatarPage.xaml" />
<None Remove="View\Page\WikiMonsterPage.xaml" />
<None Remove="View\Page\WikiWeaponPage.xaml" />
<None Remove="View\TitleView.xaml" />
<None Remove="View\UserView.xaml" />
@@ -150,6 +152,7 @@
<Content Include="Resource\Icon\UI_ItemIcon_210.png" />
<Content Include="Resource\Icon\UI_ItemIcon_210_256.png" />
<Content Include="Resource\Icon\UI_ItemIcon_220021.png" />
<Content Include="Resource\Icon\UI_MarkCustom_TagMonster.png" />
<Content Include="Resource\Icon\UI_MarkQuest_Events_Proce.png" />
<Content Include="Resource\Icon\UI_MarkTower.png" />
<Content Include="Resource\Icon\UI_MarkTower_Tower.png" />
@@ -443,6 +446,11 @@
<LastGenOutput>SH.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Page Update="View\Page\WikiMonsterPage.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Page Update="View\Control\BaseValueSlider.xaml">
<Generator>MSBuild:Compile</Generator>

View File

@@ -24,7 +24,8 @@
VerticalAlignment="Center"
VerticalContentAlignment="Center"
Content="{shcm:ResourceString Name=ViewControlBaseValueSliderPromoted}"
IsChecked="{x:Bind BaseValueInfo.Promoted, Mode=TwoWay}"/>
IsChecked="{x:Bind BaseValueInfo.Promoted, Mode=TwoWay}"
Visibility="{x:Bind IsPromoteVisible, Converter={StaticResource BoolToVisibilityConverter}}"/>
<Slider
MinWidth="240"
Margin="16,0,8,0"
@@ -33,7 +34,6 @@
Minimum="1"
StepFrequency="1"
Value="{x:Bind BaseValueInfo.CurrentLevel, Mode=TwoWay}"/>
</StackPanel>
</wsc:Setting.ActionContent>
</wsc:Setting>

View File

@@ -14,6 +14,7 @@ namespace Snap.Hutao.View.Control;
internal sealed partial class BaseValueSlider : UserControl
{
private static readonly DependencyProperty BaseValueInfoProperty = Property<BaseValueSlider>.Depend<BaseValueInfo>(nameof(BaseValueInfo));
private static readonly DependencyProperty IsPromoteVisibleProperty = Property<BaseValueSlider>.DependBoxed<bool>(nameof(IsPromoteVisible), BoxedValues.True);
/// <summary>
/// <20><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>µĻ<C2B5><C4BB><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
@@ -31,4 +32,13 @@ internal sealed partial class BaseValueSlider : UserControl
get => (BaseValueInfo)GetValue(BaseValueInfoProperty);
set => SetValue(BaseValueInfoProperty, value);
}
/// <summary>
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ť<EFBFBD>Ƿ<EFBFBD><C7B7>ɼ<EFBFBD>
/// </summary>
public bool IsPromoteVisible
{
get { return (bool)GetValue(IsPromoteVisibleProperty); }
set { SetValue(IsPromoteVisibleProperty, value); }
}
}

View File

@@ -79,6 +79,10 @@
shvh:NavHelper.NavigateTo="shvp:WikiWeaponPage"
Content="{shcm:ResourceString Name=ViewWikiWeaponHeader}"
Icon="{shcm:BitmapIcon Source=ms-appx:///Resource/Icon/UI_BagTabIcon_Weapon.png}"/>
<NavigationViewItem
shvh:NavHelper.NavigateTo="shvp:WikiMonsterPage"
Content="{shcm:ResourceString Name=ViewWikiMonsterHeader}"
Icon="{shcm:BitmapIcon Source=ms-appx:///Resource/Icon/UI_MarkCustom_TagMonster.png}"/>
</NavigationView.MenuItems>
<NavigationView.PaneFooter>

View File

@@ -300,7 +300,6 @@
Text="养成材料"/>
<GridView
Margin="16,16,0,0"
ItemsPanel="{StaticResource HorizontalStackPanelTemplate}"
ItemsSource="{Binding Selected.CultivationItemsView}"
SelectionMode="None">
<ItemsControl.ItemTemplate>

View File

@@ -0,0 +1,205 @@
<shc:ScopedPage
x:Class="Snap.Hutao.View.Page.WikiMonsterPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cwuc="using:CommunityToolkit.WinUI.UI.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:mxi="using:Microsoft.Xaml.Interactivity"
xmlns:mxic="using:Microsoft.Xaml.Interactions.Core"
xmlns:shc="using:Snap.Hutao.Control"
xmlns:shcb="using:Snap.Hutao.Control.Behavior"
xmlns:shci="using:Snap.Hutao.Control.Image"
xmlns:shcm="using:Snap.Hutao.Control.Markup"
xmlns:shcp="using:Snap.Hutao.Control.Panel"
xmlns:shv="using:Snap.Hutao.ViewModel"
xmlns:shvc="using:Snap.Hutao.View.Control"
xmlns:wsc="using:WinUICommunity.SettingsUI.Controls"
d:DataContext="{d:DesignInstance Type=shv:WikiMonsterViewModel}"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
mc:Ignorable="d">
<mxi:Interaction.Behaviors>
<shcb:InvokeCommandOnLoadedBehavior Command="{Binding OpenUICommand}"/>
</mxi:Interaction.Behaviors>
<Grid>
<Grid Visibility="{Binding Monsters, Converter={StaticResource EmptyObjectToVisibilityConverter}}">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<CommandBar
Grid.Row="0"
Background="{StaticResource CardBackgroundFillColorDefaultBrush}"
BorderBrush="{x:Null}"
BorderThickness="0"
DefaultLabelPosition="Right">
<CommandBar.Content>
<shcp:PanelSelector x:Name="ItemsPanelSelector" Margin="6,8,0,0"/>
</CommandBar.Content>
<AppBarElementContainer Visibility="Collapsed">
<AutoSuggestBox
Width="240"
Height="36"
Margin="16,6,6,0"
HorizontalAlignment="Stretch"
VerticalContentAlignment="Center"
PlaceholderText="筛选怪物"
QueryIcon="{shcm:FontIcon Glyph=&#xE721;}"
Text="{Binding FilterText, Mode=TwoWay}">
<mxi:Interaction.Behaviors>
<mxic:EventTriggerBehavior EventName="QuerySubmitted">
<mxic:InvokeCommandAction Command="{Binding FilterCommand}" CommandParameter="{Binding FilterText}"/>
</mxic:EventTriggerBehavior>
</mxi:Interaction.Behaviors>
</AutoSuggestBox>
</AppBarElementContainer>
</CommandBar>
<SplitView
Grid.Row="1"
DisplayMode="Inline"
IsPaneOpen="True"
OpenPaneLength="{StaticResource CompatSplitViewOpenPaneLength2}"
PaneBackground="{StaticResource CardBackgroundFillColorSecondary}">
<SplitView.Pane>
<cwuc:SwitchPresenter Grid.Row="1" Value="{Binding ElementName=ItemsPanelSelector, Path=Current}">
<cwuc:Case Value="List">
<ListView
Grid.Row="1"
ItemsSource="{Binding Monsters}"
SelectedItem="{Binding Selected, Mode=TwoWay}"
SelectionMode="Single">
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Style="{StaticResource BaseTextBlockStyle}" Text="{Binding Key}"/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListView.GroupStyle>
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<shci:CachedImage
Grid.Column="0"
Width="48"
Height="48"
Margin="0,6,12,6"
Source="{Binding Icon, Converter={StaticResource MonsterIconConverter}, Mode=OneWay}"/>
<TextBlock
Grid.Column="1"
Margin="12,0,0,0"
VerticalAlignment="Center"
Text="{Binding Title}"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</cwuc:Case>
<cwuc:Case Value="Grid">
<GridView
Margin="6,6,0,0"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Left"
ItemsSource="{Binding Monsters}"
SelectedItem="{Binding Selected, Mode=TwoWay}"
SelectionMode="Single">
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsWrapGrid Orientation="Horizontal"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
<GridView.ItemTemplate>
<DataTemplate>
<shvc:ItemIcon
Width="46"
Height="46"
Icon="{Binding Icon, Converter={StaticResource MonsterIconConverter}, Mode=OneWay}"
Quality="QUALITY_NONE"/>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
</cwuc:Case>
</cwuc:SwitchPresenter>
</SplitView.Pane>
<SplitView.Content>
<ScrollViewer>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition MaxWidth="800"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<StackPanel Margin="0,0,20,0">
<TextBlock
Margin="16,16,0,0"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Style="{StaticResource SubtitleTextBlockStyle}"
Text="{Binding Selected.Title}"/>
<ItemsControl Margin="16,8,0,0" ItemsSource="{Binding Selected.Affixes}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<cwuc:WrapPanel HorizontalSpacing="8" Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<shvc:BaseValueSlider
Margin="16,16,0,0"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
BaseValueInfo="{Binding BaseValueInfo, Mode=OneWay}"
IsPromoteVisible="False"/>
<ItemsControl Margin="16,16,0,0" ItemsSource="{Binding Selected.BaseValue.SubHurts}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<cwuc:UniformGrid
ColumnSpacing="2"
Columns="2"
RowSpacing="2"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<wsc:Setting Header="{Binding Name}">
<TextBlock Text="{Binding Value}"/>
</wsc:Setting>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBlock
Margin="16,32,0,0"
Style="{StaticResource BaseTextBlockStyle}"
Text="{shcm:ResourceString Name=ViewPageWikiMonsterDropItems}"
Visibility="{Binding Selected.DropsView, Converter={StaticResource EmptyObjectToVisibilityConverter}}"/>
<GridView
Margin="16,16,-4,12"
Padding="0"
ItemsSource="{Binding Selected.DropsView}"
SelectionMode="None"
Visibility="{Binding Selected.DropsView, Converter={StaticResource EmptyObjectToVisibilityConverter}}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<shvc:BottomTextControl Text="{Binding Name}">
<shvc:ItemIcon Icon="{Binding Icon, Converter={StaticResource ItemIconConverter}}" Quality="{Binding RankLevel}"/>
</shvc:BottomTextControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</GridView>
</StackPanel>
</Grid>
</ScrollViewer>
</SplitView.Content>
</SplitView>
</Grid>
<shvc:LoadingView IsLoading="{Binding Monsters, Converter={StaticResource EmptyObjectToBoolRevertConverter}}"/>
</Grid>
</shc:ScopedPage>

View File

@@ -0,0 +1,22 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
using Snap.Hutao.Control;
using Snap.Hutao.ViewModel;
namespace Snap.Hutao.View.Page;
/// <summary>
/// 怪物资料页面
/// </summary>
internal sealed partial class WikiMonsterPage : ScopedPage
{
/// <summary>
/// 构造一个新的怪物资料页面
/// </summary>
public WikiMonsterPage()
{
InitializeComponent();
InitializeWith<WikiMonsterViewModel>();
}
}

View File

@@ -195,28 +195,31 @@
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
BaseValueInfo="{Binding BaseValueInfo, Mode=OneWay}"/>
<TextBlock
Margin="16,32,0,0"
Style="{StaticResource BaseTextBlockStyle}"
Text="{Binding Selected.Affix.Name}"/>
<Pivot ItemsSource="{Binding Selected.Affix.Descriptions}">
<Pivot.HeaderTemplate>
<DataTemplate>
<TextBlock Style="{StaticResource CaptionTextBlockStyle}" Text="{Binding LevelFormatted}"/>
</DataTemplate>
</Pivot.HeaderTemplate>
<Pivot.ItemTemplate>
<DataTemplate>
<shct:DescriptionTextBlock Margin="16,16,0,0" Description="{Binding Description}">
<shct:DescriptionTextBlock.Resources>
<Style BasedOn="{StaticResource BodyTextBlockStyle}" TargetType="TextBlock">
<Setter Property="TextWrapping" Value="Wrap"/>
</Style>
</shct:DescriptionTextBlock.Resources>
</shct:DescriptionTextBlock>
</DataTemplate>
</Pivot.ItemTemplate>
</Pivot>
<StackPanel Visibility="{Binding Selected.Affix, Converter={StaticResource EmptyObjectToVisibilityConverter}}">
<TextBlock
Margin="16,32,0,0"
Style="{StaticResource BaseTextBlockStyle}"
Text="{Binding Selected.Affix.Name}"/>
<Pivot ItemsSource="{Binding Selected.Affix.Descriptions}">
<Pivot.HeaderTemplate>
<DataTemplate>
<TextBlock Style="{StaticResource CaptionTextBlockStyle}" Text="{Binding LevelFormatted}"/>
</DataTemplate>
</Pivot.HeaderTemplate>
<Pivot.ItemTemplate>
<DataTemplate>
<shct:DescriptionTextBlock Margin="16,16,0,0" Description="{Binding Description}">
<shct:DescriptionTextBlock.Resources>
<Style BasedOn="{StaticResource BodyTextBlockStyle}" TargetType="TextBlock">
<Setter Property="TextWrapping" Value="Wrap"/>
</Style>
</shct:DescriptionTextBlock.Resources>
</shct:DescriptionTextBlock>
</DataTemplate>
</Pivot.ItemTemplate>
</Pivot>
</StackPanel>
<TextBlock
Margin="16,32,0,0"
Style="{StaticResource BaseTextBlockStyle}"

View File

@@ -5,6 +5,7 @@ using CommunityToolkit.Mvvm.Input;
using Microsoft.Extensions.DependencyInjection;
using Snap.Hutao.Model.Binding.Cultivation;
using Snap.Hutao.Model.Entity;
using Snap.Hutao.Model.Metadata.Item;
using Snap.Hutao.Service.Abstraction;
using Snap.Hutao.Service.Cultivation;
using Snap.Hutao.Service.Metadata;
@@ -186,7 +187,7 @@ internal sealed class CultivationViewModel : Abstraction.ViewModel
{
if (project != null)
{
List<Model.Metadata.Material> materials = await metadataService.GetMaterialsAsync().ConfigureAwait(false);
List<Material> materials = await metadataService.GetMaterialsAsync().ConfigureAwait(false);
ObservableCollection<CultivateEntryView> entries = await cultivationService
.GetCultivateEntriesAsync(project)

View File

@@ -46,10 +46,10 @@ internal sealed class SettingViewModel : Abstraction.ViewModel
private readonly List<NameValue<string>> cultures = new()
{
new("简体中文", "zh-CN"),
new("繁體中文", "zh-TW"),
new("English (United States)", "en-US"),
new("한국인", "ko-KR"),
ToNameValue(CultureInfo.CreateSpecificCulture("zh-CN")),
ToNameValue(CultureInfo.CreateSpecificCulture("zh-TW")),
ToNameValue(CultureInfo.CreateSpecificCulture("en-US")),
ToNameValue(CultureInfo.CreateSpecificCulture("ko-KR")),
};
private bool isEmptyHistoryWishVisible;
@@ -226,6 +226,11 @@ internal sealed class SettingViewModel : Abstraction.ViewModel
/// </summary>
public ICommand ResetStaticResourceCommand { get; }
private static NameValue<string> ToNameValue(CultureInfo info)
{
return new(info.NativeName, info.Name);
}
private async Task SetGamePathAsync()
{
IGameLocator locator = serviceProvider.GetRequiredService<IEnumerable<IGameLocator>>()

View File

@@ -12,6 +12,7 @@ using Snap.Hutao.Model.Intrinsic;
using Snap.Hutao.Model.Intrinsic.Immutable;
using Snap.Hutao.Model.Metadata;
using Snap.Hutao.Model.Metadata.Avatar;
using Snap.Hutao.Model.Metadata.Item;
using Snap.Hutao.Model.Primitive;
using Snap.Hutao.Service.Abstraction;
using Snap.Hutao.Service.Cultivation;
@@ -139,7 +140,7 @@ internal sealed class WikiAvatarViewModel : Abstraction.ViewModel
{
avatar.Collocation = idCollocations.GetValueOrDefault(avatar.Id);
avatar.CookBonusView ??= CookBonusView.Create(avatar.FetterInfo.CookBonus2, idMaterialMap);
avatar.CultivationItemsView ??= avatar.CultivationItems.Select(i => idMaterialMap[i]).ToList();
avatar.CultivationItemsView ??= avatar.CultivationItems.SelectList(i => idMaterialMap[i]);
}
}
}

View File

@@ -0,0 +1,132 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
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.Item;
using Snap.Hutao.Model.Metadata.Monster;
using Snap.Hutao.Model.Metadata.Weapon;
using Snap.Hutao.Model.Primitive;
using Snap.Hutao.Service.Abstraction;
using Snap.Hutao.Service.Cultivation;
using Snap.Hutao.Service.Hutao;
using Snap.Hutao.Service.Metadata;
using Snap.Hutao.Service.User;
using Snap.Hutao.View.Dialog;
using Snap.Hutao.Web.Response;
using System.Collections.Immutable;
using System.Runtime.InteropServices;
using CalcAvatarPromotionDelta = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.AvatarPromotionDelta;
using CalcClient = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.CalculateClient;
using CalcConsumption = Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate.Consumption;
namespace Snap.Hutao.ViewModel;
/// <summary>
/// 怪物资料视图模型
/// </summary>
[Injection(InjectAs.Scoped)]
internal class WikiMonsterViewModel : Abstraction.ViewModel
{
private readonly IServiceProvider serviceProvider;
private readonly IMetadataService metadataService;
private readonly IHutaoCache hutaoCache;
private AdvancedCollectionView? monsters;
private Monster? selected;
private string? filterText;
private BaseValueInfo? baseValueInfo;
private Dictionary<int, Dictionary<GrowCurveType, float>>? levelMonsterCurveMap;
private Dictionary<MaterialId, Material>? idMaterialMap;
/// <summary>
/// 构造一个新的怪物资料视图模型
/// </summary>
/// <param name="serviceProvider">服务提供器</param>
public WikiMonsterViewModel(IServiceProvider serviceProvider)
{
metadataService = serviceProvider.GetRequiredService<IMetadataService>();
hutaoCache = serviceProvider.GetRequiredService<IHutaoCache>();
this.serviceProvider = serviceProvider;
OpenUICommand = new AsyncRelayCommand(OpenUIAsync);
}
/// <summary>
/// 角色列表
/// </summary>
public AdvancedCollectionView? Monsters { get => monsters; set => SetProperty(ref monsters, value); }
/// <summary>
/// 选中的角色
/// </summary>
public Monster? 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>
public string? FilterText { get => filterText; set => SetProperty(ref filterText, value); }
/// <summary>
/// 打开界面命令
/// </summary>
public ICommand OpenUICommand { get; }
private async Task OpenUIAsync()
{
if (await metadataService.InitializeAsync().ConfigureAwait(false))
{
levelMonsterCurveMap = await metadataService.GetLevelToMonsterCurveMapAsync().ConfigureAwait(false);
List<Monster> monsters = await metadataService.GetMonstersAsync().ConfigureAwait(false);
Dictionary<MaterialId, Display> idDisplayMap = await metadataService.GetIdToDisplayAndMaterialMapAsync().ConfigureAwait(false);
foreach (Monster monster in monsters)
{
monster.DropsView ??= monster.Drops?.SelectList(i => idDisplayMap.GetValueOrDefault(i)!);
}
List<Monster> ordered = monsters.OrderBy(m => m.Id.Value).ToList();
await ThreadHelper.SwitchToMainThreadAsync();
Monsters = new AdvancedCollectionView(ordered, true);
Selected = Monsters.Cast<Monster>().FirstOrDefault();
}
}
private void UpdateBaseValueInfo(Monster? monster)
{
if (monster == null)
{
BaseValueInfo = null;
}
else
{
List<PropertyCurveValue> propertyCurveValues = monster.GrowCurves
.Select(curveInfo => new PropertyCurveValue(curveInfo.Key, curveInfo.Value, monster.BaseValue.GetValue(curveInfo.Key)))
.ToList();
BaseValueInfo = new(100, propertyCurveValues, levelMonsterCurveMap!);
}
}
}

View File

@@ -145,12 +145,7 @@ 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";